I'm trying to make a test to submit JSON data to my API endpoint, however it's not working. After trying various suggestions from blogs and the rspec documentation I'm still failing.
specs/controller/v1/devices_controller_spec.rb
require 'rails_helper'
RSpec.describe V1::DevicesController, type: :controller do
it "updates device info" do
#data = {}
#device = FactoryGirl.create(:device)
#data[:diagnostic_dns] = false
#data[:diagnostic_ping] = false
put :update, #data.to_json
#data.reload
response.should be_successful
end
end
I've also tried this in my test:
it "updates device info" do
device = FactoryGirl.create(:device)
device.diagnostic_dns = false
device.diagnostic_ping = false
put :update, :device, :format => :json
response.should be_successful
end
Which results in this rspec failure:
Failures:
1) V1::DevicesController updates device info
Failure/Error: put :update, #data.to_json
ArgumentError:
wrong number of arguments (given 2, expected 1)
app/controllers/v1/devices_controller.rb
class V1::DevicesController < ApplicationController
skip_before_action :authenticate_user!, only: [:show, :update], :if => Proc.new { |c| c.request.format == 'application/json' }
before_action :set_device, only: [:show, :update]
respond_to :json
def update
if #device.update(device_params)
render json: #device, status: :ok
else
render json: #device.errors, status: :unprocessable_entity
end
end
private
def set_device
#device = Device.find_by!(serial_number: params[:serial_number])
end
def device_params
params.require(:device).permit(
:serial_number,
:name,
:diagnostic_checkin_status,
:diagnostic_dns,
:diagnostic_ping,
)
end
end
And my routes.rb file
v1_device GET /v1/devices/:serial_number(.:format) v1/devices#show
PATCH /v1/devices/:serial_number(.:format) v1/devices#update
PUT /v1/devices/:serial_number(.:format) v1/devices#update
UPDATE
After changing my test submit to:
patch :update, params: {serial_number: device.serial_number, device: #data }, :format => :json
I'm now getting:
Failures:
1) V1::DevicesController updates device info
Failure/Error: response.should be_successful
expected `#<ActionDispatch::TestResponse:0x005592458af9d0 #mon_owner=nil, #mon_count=0, #mon_mutex=#<Thread::Mu...:Headers:0x00559245826d10 #req=#<ActionController::TestRequest:0x005592458afcc8 ...>>, #variant=[]>>.successful?` to return true, got false
UPDATE
I added byebug to the controller and this is what #device.errors has it in:
#messages={:diagnostic_ping=>["can't be blank"], :diagnostic_dns=>["can't be blank"]}, #details={:diagnostic_ping=>[{:error=>:blank}], :diagnostic_dns=>[{:error=>:blank}]}>
So, the variables are not being set?
To adding parameter, you can use this.
specs/controller/v1/devices_controller_spec.rb
require 'rails_helper'
RSpec.describe V1::DevicesController, type: :controller do
let(:new_attributes) {
FactoryGirl.attributes_for :device, diagnostic_dns: false, diagnostic_ping: false
}
it "updates device info" do
#device = FactoryGirl.create :device
put :update, params: {serial_number: #device.serial_number, device: new_attributes }, :format => :json
response.should be_successful
end
end
I hope this help you.
I wouldn't stress too much about getting RSpec to submit an actual JSON string to your code. Rails is in charge of turning that JSON into a params hash for you, so Rails should have the tests verifying they handle JSON properly. I would just do a normal test passing params with a format: :json verifying that you return the JSON you're expecting.
I believe that would look like
put :update, serial_number: #device.serial_number, device: #data, format: :json
Related
I used this tutorial to generate an API for my Rails 5 app.
This is between Comments and Post tables. Post has a 1:m relationship with Comment.
But rspec fails every test. I have checked my files and hierarchy over and over again, still not seeing where the problem is.
Here is the output of rails routes:
Prefix Verb URI Pattern Controller#Action
post_comments GET /posts/:post_id/comments(.:format) comments#index
POST /posts/:post_id/comments(.:format) comments#create
post_comment GET /posts/:post_id/comments/:id(.:format) comments#show
PATCH /posts/:post_id/comments/:id(.:format) comments#update
PUT /posts/:post_id/comments/:id(.:format) comments#update
DELETE /posts/:post_id/comments/:id(.:format) comments#destroy
post_like POST /posts/:post_id/like(.:format) posts#like
post_dislike POST /posts/:post_id/dislike(.:format) posts#dislike
posts GET /posts(.:format) posts#index
POST /posts(.:format) posts#create
post GET /posts/:id(.:format) posts#show
PATCH /posts/:id(.:format) posts#update
PUT /posts/:id(.:format) posts#update
DELETE /posts/:id(.:format) posts#destroy
my config/routes.rb:
Rails.application.routes.draw do
resources :posts do
resources :comments
post :like
post :dislike
end
end
application_controller.rb: (Even with ActionController::API, it does not work)
class ApplicationController < ActionController::Base
include Response
include ExceptionHandler
protect_from_forgery with: :exception
end
My comments_controller.rb
class CommentsController < ApplicationController
before_action :set_post
before_action :set_post_comment, only: [:show, :update, :destroy]
# GET /comments
# GET /comments.json
def index
##comments = Comment.all
json_response(#post.comments)
end
# GET /comments/1
# GET /comments/1.json
def show
json_response(#comment)
end
# POST /comments
# POST /comments.json
def create
#comment = Comment.new(comment_params)
#post.comments.create!(comment_params)
json_response(#post, :created)
if #comment.save
render :show, status: :created, location: #comment
else
render json: #comment.errors, status: :unprocessable_entity
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_comment
#comment = Comment.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def comment_params
params.require(:comment).permit(:commenter, :comment, :description, :post)
end
def set_post
#post = Post.find(params[:post_id])
end
def set_post_comment
#comment = #post.comments.find_by!(id: params[:id]) if #post
end
end
Finally, the posts_controller.rb:
class PostsController < ApplicationController
before_action :set_post, only: [:show, :update, :destroy]
# GET /posts
# GET /posts.json
def index
#posts = Post.all
json_response(#posts)
end
# GET /posts/1
# GET /posts/1.json
def show
json_response(#post)
end
# POST /posts
# POST /posts.json
def create
#post = Post.new(post_params)
json_response(#post, :created)
if #post.save
render :show, status: :created, location: #post
else
render json: #post.errors, status: :unprocessable_entity
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_post
#post = Post.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def post_params
params.require(:post).permit(:poster, :vote, :description, :comment, :user_id, :image_base)
end
end
UPDATE: showing spec files
my spec/requests/comments_spec.rb:
require 'rails_helper'
RSpec.describe "Comments", type: :request do
# Initialize the test data
let!(:post) { create(:post) }
let!(:comments) { create_list(:comment, 20, post_id: post.id) }
let(:post_id) { post.id }
let(:id) { comments.first.id }
# Test suite for GET /posts/:post_id/comments
describe 'GET /posts/:post_id/comments' do
before { get "/posts/#{post_id}/comments" }
context 'when post exists' do
it 'returns status code 200' do
expect(response).to have_http_status(200)
end
it 'returns all post comments' do
expect(json.size).to eq(20)
end
end
context 'when post does not exist' do
let(:post_id) { 0 }
it 'returns status code 404' do
expect(response).to have_http_status(404)
end
it 'returns a not found message' do
expect(response.body).to match(/Couldn't find Post/)
end
end
end
# Test suite for GET /posts/:post_id/comments/:id
describe 'GET /posts/:post_id/comments/:id' do
before { get "/posts/#{post_id}/comments/#{id}" }
context 'when post item exists' do
it 'returns status code 200' do
expect(response).to have_http_status(200)
end
it 'returns the item' do
expect(json['id']).to eq(id)
end
end
context 'when post item does not exist' do
let(:id) { 0 }
it 'returns status code 404' do
expect(response).to have_http_status(404)
end
it 'returns a not found message' do
expect(response.body).to match(/Couldn't find Comment/)
end
end
end
# Test suite for PUT /posts/:post_id/comments
describe 'POST /posts/:post_id/comments' do
let(:valid_attributes) { { comment: 'A Comment', commenter: 'Luke Shaw' } }
context 'when request attributes are valid' do
before { post "/posts/#{post_id}/comments", params: valid_attributes }
it 'returns status code 201' do
expect(response).to have_http_status(201)
end
end
context 'when an invalid request' do
before { post "/posts/#{post_id}/comments", params: {} }
it 'returns status code 422' do
expect(response).to have_http_status(422)
end
it 'returns a failure message' do
expect(response.body).to match(/Validation failed: Commenter or Comment can't be blank/)
end
end
end
end
The spec/requests/posts_spec.rb:
require 'rails_helper'
RSpec.describe "Posts", type: :request do
# initialize test data
let!(:posts) { create_list(:post, 10) }
let(:post_id) { posts.first.id }
describe "GET /posts" do
# make HTTP get request before each example
before { get '/posts' }
it 'returns posts' do
# Note `json` is a custom helper to parse JSON responses
expect(json).not_to be_empty
expect(json.size).to eq(10)
end
it 'returns status code 200' do
expect(response).to have_http_status(200)
end
end
# Test suite for GET /posts/:id
describe 'GET /posts/:id' do
before { get "/posts/#{post_id}" }
context 'when the record exists' do
it 'returns the post' do
expect(json).not_to be_empty
expect(json['id']).to eq(post_id)
end
it 'returns status code 200' do
expect(response).to have_http_status(200)
end
end
context 'when the record does not exist' do
let(:post_id) { 100 }
it 'returns status code 404' do
expect(response).to have_http_status(404)
end
it 'returns a not found message' do
expect(response.body).to match(/Couldn't find Post/)
end
end
end
The spec/models/post_spec.rb:
require 'rails_helper'
RSpec.describe Post, type: :model do
# Association test
# ensure Post model has a 1:m relationship with the Comment model
it { should have_many(:comments).dependent(:destroy) }
# Validation tests
# ensure columns are present before saving
it { should validate_presence_of(:poster) }
it { should validate_presence_of(:description) }
end
ANd spec/models/comment_spec.rb:
require 'rails_helper'
RSpec.describe Comment, type: :model do
# Association test
# ensure a comment record belongs to a single post record
it { should belong_to(:post) }
# Validation test
# ensure column name is present before saving
it { should validate_presence_of(:comment) }
it { should validate_presence_of(:commenter) }
end
UPDATE 2: Showing spec/factories/*.rb files
Showing spec/factories/posts.rb:
FactoryBot.define do
factory :post do
image { Rack::Test::UploadedFile.new(Rails.root.join('public', 'system', 'posts', 'images', '000', '000', '001', 'original', 'img1.jpeg'), 'image/jpeg') }
poster { Faker::Lorem.sentence }
vote { Faker::Number.number(10).to_i}
description { Faker::Lorem.paragraph }
end
end
Showing spec/factories/comments.rb:
FactoryBot.define do
factory :comment do
commenter { Faker::Lorem.sentence }
description { Faker::Lorem.paragraph }
post_id nil
end
end
My `routes show clear inheritance and I am enforcing that in my controllers. Still, I get errors like:
Failure/Error: expect(:delete => "/comments/1").to route_to("comments#destroy", :id => "1")
No route matches "/comments/1"
AND
RuntimeError:
/home/user/projects/app/public/system/posts/images/000/000/001/original/img1.jpeg file does not exist
Ok, so the error that is causing every spec to fail is that uploaded image. It can't find the image file that you are trying to upload. Where is that image file actually located? Create that file and put it in the right place and they should start working again.
As to the routing-spec - that's the error that you included in your question, and it'll be localised to your routing-spec only (spec/routing/comments_routing_spec.rb according to your paste-bin), and will be fixed by just adjusting the routes to be the nested ones. They should include everything necessary to make the routes work (including a valid post-id).
Secondly, it should be something like:
expect(:delete => "/posts/1/comments/1").to route_to("comments#destroy", :id => "1", :post_id => "1")
Note: personally I don't bother with route-specs for simple resources, just for complex ones, but you may prefer it as a backup while you're getting used to Rails.
I'm trying to wrap my head about Rspec and Controller tests, more specifically a JSON request. In this case, I'm trying to hit the v1_devices_path route:
routes.rb
v1_device_scans POST /v1/devices/:device_serial_number/scans(.:format) v1/scans#create
v1_device GET /v1/devices/:serial_number(.:format) v1/devices#show
PATCH /v1/devices/:serial_number(.:format) v1/devices#update
PUT /v1/devices/:serial_number(.:format) v1/devices#update
And my controller:
controllers/v1/devices_controller.rb
class V1::DevicesController < ApplicationController
before_action :set_device, only: [:show, :update]
respond_to :json
def show
#device = Device.find_by(serial_number: params[:serial_number])
render :json => #device.as_json
end
def update
if #device.update(device_params)
render json: #device, status: :ok, location: #device
else
render json: #device.errors, status: :unprocessable_entity
end
end
private
def set_device
#device = Device.find_by!(serial_number: params[:serial_number])
end
def device_params
params.require(:device).permit(
:serial_number,
:name,
:diagnostic_checkin_status,
:diagnostic_dns,
:diagnostic_ping,
:assigned_internal_ip,
:assigned_external_ip,
:assigned_gateway_ip,
:version,
:timezone,
:task_id,
:scan_status,
:scan_progress
)
end
end
As of right now my test is super simple... just want to make sure I get some results back:
spec/controllers/v1/devices_controller_spec.rb
require 'rails_helper'
RSpec.describe V1::DevicesController, type: :controller do
it "shows device info" do
device = FactoryGirl.create(:device)
get v1_device_path(device.serial_number), :format => :json
expect(response.status).to be(200)
end
end
After some tweaking, I've gotten to the point where it looks like my url is being created correctly, but I'm still getting the no route matches error:
1) V1::DevicesController shows device info
Failure/Error: get v1_device_path(device.serial_number), :format => :json
ActionController::UrlGenerationError:
No route matches {:action=>"/v1/devices/41442305171c430ab253ba1ad95c5c61", :controller=>"v1/devices", :format=>:json}
# /usr/local/bundle/gems/rails-controller-testing-1.0.2/lib/rails/controller/testing/template_assertions.rb:61:in `process'
# /usr/local/bundle/gems/devise-4.3.0/lib/devise/test/controller_helpers.rb:33:in `block in process'
# /usr/local/bundle/gems/devise-4.3.0/lib/devise/test/controller_helpers.rb:100:in `catch'
# /usr/local/bundle/gems/devise-4.3.0/lib/devise/test/controller_helpers.rb:100:in `_catch_warden'
# /usr/local/bundle/gems/devise-4.3.0/lib/devise/test/controller_helpers.rb:33:in `process'
# /usr/local/bundle/gems/rails-controller-testing-1.0.2/lib/rails/controller/testing/integration.rb:12:in `block (2 levels) in <module:Integration>'
# ./spec/controllers/v1/devices_controller_spec.rb:11:in `block (2 levels) in <top (required)>'
What am I doing wrong?
This is another solution to not change type into request. This error shows because of adding serial_number parameter in show devise route, you can add serial_number in your get url.
RSpec.describe V1::DevicesController, type: :controller do
it "shows device info" do
device = FactoryGirl.create(:device)
get :show, params: { serial_number: device.serial_number }, :format => :json
expect(response.status).to be(200)
end
end
I hope this help you.
Alright, starting with #sebastián's comment, I changed the spec to:
require 'rails_helper'
RSpec.describe V1::DevicesController, type: :request do
it "shows device info" do
headers = {
"ACCEPT" => "application/json", # This is what Rails 4 accepts
}
device = FactoryGirl.create(:device)
get v1_device_path(device.serial_number), :headers => headers
expect(response.content_type).to eq("application/json")
end
end
And my test passes now.
I am getting the following error when I run rspec. Could really do with some help here! I am not sure if the nested resources or ajax calls are contributing to the rspec failure.
1) GoalsController GET #new renders the :new template
Failure/Error: expect(response).to render_template :new
expecting <"new"> but rendering with <[]>
# ./spec/controllers/goals_controller_spec.rb:7:in `block (3 levels) in <top (required)>'
Here are my codes as shown below.
routes.rb
Rails.application.routes.draw do
resources :strategies, :only => :none do
resources :goals
end
resources :goals, :only => :none do
resources :objectives
end
end
goals_controller.rb
class GoalsController < ApplicationController
respond_to :html, :js
def new
#strategy = Strategy.find(params[:strategy_id])
end
def index
#strategy = Strategy.find(params[:strategy_id])
end
def create
#user = User.find(current_user.id)
#strategy = Strategy.find(params[:strategy_id])
#goal = #strategy.goals.create(goal_params.merge(
start_date: #strategy.start_date,
end_date: #strategy.end_date,
created_by: #user.id))
respond_to do |format|
format.js { }
end
end
private
def goal_params
params.require(:goal).permit(:name, :budget)
end
end
goals_controller_spec.rb
require 'rails_helper'
RSpec.describe GoalsController, type: :controller do
describe 'GET #new' do
it "renders the :new template" do
get :new, strategy_id: 2
expect(response).to render_template :new
end
end
end
Like Sergey Sokolov suggested in the comment, try removing all :only => :none
in the routes.
resources will generate routes for all CRUD actions,:only => :none is basically saying you don't want it to generate at all.
I have a problem with redirecting and testing it in rspec
I have a problem with test not passing when I use a get method, but are green for the same code base when I use a put method. I don't know how to work around this and need assistance in making tests pass.
I get a 200 HTTP status code, but I want to get confirmation on redirect, so that it could be tracked by rspec. What code basically needs to do is redirect logged in user who is not owner of a product to category_product_url(category, product) with a flash error: 'You are not allowed to edit this product.' when trying to edit product with get http method.
Used gems rspec-rails, devise and decent_exposure. Ruby 2.1.5 and Rails 4.1.8
Actual error message:
Failure/Error: expect(response).to redirect_to(category_product_url(category, product))
Expected response to be a <redirect>, but was <200>
Failure/Error: expect(controller.flash[:error]).to eq 'You are not allowed to edit this product.'
expected: "You are not allowed to edit this product."
got: nil
(compared using ==)
My spec
context 'another user is singed in' do
let(:user) { create(:user) }
let(:user2) { build(:user) }
let(:product) { Product.create! valid_attributes }
before do
sign_in user2
controller.stub(:user_signed_in?).and_return(true)
controller.stub(:current_user).and_return(user2)
controller.stub(:authenticate_user!).and_return(user2)
product.user = user
end
describe 'GET edit' do
describe 'with valid params' do
it 'redirects to product page' do
get :edit, { id: product.to_param, category_id: category.to_param }
expect(response).to redirect_to(category_product_url(category, product))
end
it 'renders error message' do
get :edit, { id: product.to_param, category_id: category.to_param }
expect(controller.flash[:error]).to eq 'You are not allowed to edit this product.'
end
end
end
My controller
before_action :authenticate_user!, only: [:new, :edit, :update, :destroy, :create]
expose(:category)
expose(:products)
expose(:product)
def edit
end
def update
if product.user == current_user
if self.product.update(product_params)
redirect_to category_product_url(category, product), notice: 'Product was successfully updated.'
else
render action: 'edit'
end
else
redirect_to category_product_url(category, product), flash: { error: 'You are not allowed to edit this product.' }
end
end
private
def product_params
params.require(:product).permit(:title, :description, :price, :category_id, :user_id)
end
What is strange, is that put method is working fine with the same update action. Following specs are passing
describe 'PUT update' do
describe 'with valid params' do
it 'redirects to product page' do
put :update, { id: product.to_param, product: { 'title' => 'MyString' }, category_id: category.to_param }
expect(response).to redirect_to(category_product_url(category, product))
end
it 'does not update product' do
put :update, { id: product.to_param, product: { 'title' => 'MyNewString' }, category_id: category.to_param }
expect(controller.product.title).to_not eq 'MyNewString'
end
it 'renders error message' do
put :update, { id: product.to_param, product: { 'title' => 'MyString' }, category_id: category.to_param }
expect(controller.flash[:error]).to eq 'You are not allowed to edit this product.'
end
end
end
The way how decent_exposure and devise work, you need to first invoke a before_action method passing there a private method of your choice.
For this particular example your controller should contain this
before_action :author!, only: [:edit, :update]
and a private method filter
def author!
unless self.product.user == current_user
redirect_to category_product_url(category, product),
flash: { error: 'You are not allowed to edit this product.' }
end
end
This way you get your get http requests and put http requests pass the specs.
Try this
expect(:get => "/products/1/edit").to route_to(:controller => "controller_name", :action => "action_name")
Hope this will work.
Even when the following line works just fine on the model test:
game = FactoryGirl.create(:game)
It doesn't seem to do it on games_controller_rspec.rb.
describe "GET index" do
it "assigns all games as #games" do
game = FactoryGirl.create(:game)
get :index, {}
expect(assigns(:games)).to eq([game])
end
end
And I keep getting "expected: [...]
got: nil"
This is the factory:
FactoryGirl.define do
factory :game do |f|
f.team_a_id { 1 }
f.team_b_id { 2 }
end
end
Full games_controller.rb:
class GamesController < ApplicationController
before_action :set_game, only: [:show, :edit, :update, :destroy]
before_filter :check_admin_status, only: [:new, :edit, :create, :update, :destroy]
def index
#games = Game.all
end
def show
end
def new
#game = Game.new
end
def edit
end
def create
#game = Game.new(game_params)
respond_to do |format|
if #game.save
format.html { redirect_to #game, notice: 'Game was successfully created.' }
format.json { render action: 'show', status: :created, location: #game }
else
format.html { render action: 'new' }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
end
end
def update
respond_to do |format|
if #game.update(game_params)
format.html { redirect_to #game, notice: 'Game was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: 'edit' }
format.json { render json: #game.errors, status: :unprocessable_entity }
end
end
end
def destroy
#game.destroy
respond_to do |format|
format.html { redirect_to games_url }
format.json { head :no_content }
end
end
private
def set_game
#game = Game.find(params[:id])
end
def game_params
params.require(:game).permit(:team_a_id, :team_b_id)
end
end
Full games_controller_spec.rb:
require 'spec_helper'
describe GamesController do
include Devise::TestHelpers
let(:valid_attributes) { { "team_a_id" => "1" } }
let(:valid_session) { {} }
describe "GET index" do
it "assigns all games as #games" do
game = FactoryGirl.create(:game)
get :index, {}
expect(assigns(:games)).to eq([game])
end
end
describe "GET show" do
it "assigns the requested game as #game" do
game = FactoryGirl.create(:game)
get :show, {:id => game.to_param}, valid_session
expect(assigns(:game)).to eq(game)
end
end
describe "GET new" do
it "assigns a new game as #game" do
get :new, {}, valid_session
expect(assigns(:game)).to be_a_new(Game)
end
end
describe "GET edit" do
it "assigns the requested game as #game" do
game = FactoryGirl.create(:game)
get :edit, {:id => game.to_param}, valid_session
expect(assigns(:game)).to eq(game)
end
end
describe "POST create" do
describe "with valid params" do
it "creates a new Game" do
expect {
post :create, {:game => valid_attributes}, valid_session
}.to change(Game, :count).by(1)
end
it "assigns a newly created game as #game" do
post :create, {:game => valid_attributes}, valid_session
expect(assigns(:game)).to be_a(Game)
expect(assigns(:game)).to be_persisted
end
it "redirects to the created game" do
post :create, {:game => valid_attributes}, valid_session
expect(response).to redirect_to(Game.last)
end
end
describe "with invalid params" do
it "assigns a newly created but unsaved game as #game" do
allow_any_instance_of(Game).to receive(:save).and_return(false)
post :create, {:game => { "team_a_id" => "invalid value" }}, valid_session
expect(assigns(:game)).to be_a_new(Game)
end
it "re-renders the 'new' template" do
allow_any_instance_of(Game).to receive(:save).and_return(false)
post :create, {:game => { "team_a_id" => "invalid value" }}, valid_session
expect(response).to render_template("new")
end
end
end
describe "PUT update" do
describe "with valid params" do
it "updates the requested game" do
game = Game.create! valid_attributes
expect_any_instance_of(Game).to receive(:update).with({ "team_a_id" => "1" })
put :update, {:id => game.to_param, :game => { "team_a_id" => "1" }}, valid_session
end
it "assigns the requested game as #game" do
game = Game.create! valid_attributes
put :update, {:id => game.to_param, :game => valid_attributes}, valid_session
expect(assigns(:game)).to eq(game)
end
it "redirects to the game" do
game = Game.create! valid_attributes
put :update, {:id => game.to_param, :game => valid_attributes}, valid_session
expect(response).to redirect_to(game)
end
end
describe "with invalid params" do
it "assigns the game as #game" do
game = Game.create! valid_attributes
allow_any_instance_of(Game).to receive(:save).and_return(false)
put :update, {:id => game.to_param, :game => { "team_a_id" => "invalid value" }}, valid_session
expect(assigns(:game)).to eq(game)
end
it "re-renders the 'edit' template" do
game = Game.create! valid_attributes
allow_any_instance_of(Game).to receive(:save).and_return(false)
put :update, {:id => game.to_param, :game => { "team_a_id" => "invalid value" }}, valid_session
expect(response).to render_template("edit")
end
end
end
describe "DELETE destroy" do
it "destroys the requested game" do
game = Game.create! valid_attributes
expect {
delete :destroy, {:id => game.to_param}, valid_session
}.to change(Game, :count).by(-1)
end
it "redirects to the games list" do
game = Game.create! valid_attributes
delete :destroy, {:id => game.to_param}, valid_session
expect(response).to redirect_to(games_url)
end
end
end
Found it. The problem was with user privileges. I'm using devise and only allow certain methods to regular users. Therefore the result for them would be nil, unless i take the test with an admin user.
Basically I had to set an admin user on spec to make it work.
This is how you do it:
1) Write controller_macros.rb inside spec/support
module ControllerMacros
def login_admin
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:admin]
sign_in FactoryGirl.create(:admin) # Using factory girl as an example
end
end
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
user.confirm!
sign_in user
end
end
end
2) Add it to spec_helper
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.extend ControllerMacros, :type => :controller
end
3) Set the user to admin on your controller_spec
describe GamesController do
login_admin
describe "GET index" do
game = FactoryGirl.create(:game)
get :index, {}, valid_session
expect(assigns(:games).to eq([game])
end
My User factory:
FactoryGirl.define do
factory :user do
email "nn#nnn.com"
password "12345654321"
password_confirmation { "12345654321" }
factory :admin do
after(:create) { |user| user.update_attribute :admin, true }
end
end
end
Founded here.
I'm having the same exact issue. I found a post on here (I forgot to bookmark it and am having trouble finding it) that said to replace your "get :index, {}" with "controller.index" and see if it works. It worked for me when I did this. They also said it was a routing issue. What I don't understand is why, and how to fix it so that I can use the standard code that's generated from the scaffold. My route tests pass, but yet there's a routing issue that's causing "get" not to work in these tests? I don't understand.
EDIT:
Just found the post. Check it out here. The OP never comes back to tell what the issue was our how they fixed it though. I would love to know as I'm frustrated trying to figure out how to get this working.