I have this action in controller:
def update
#board = Board.find(params[:board_id])
#category = Category.find(params[:id])
if #category.update_attributes(category_params)
flash[:notice] = "You sucessfully changed category name."
redirect_to settings_board_path(#board)
else
render :edit
end
end
And problem with this test case:
context "with invalid attributes" do
let(:updated_category) { FactoryGirl.attributes_for(:category, name: "") }
it "re-renders :edit template" do
patch :create, board_id: board, id: category, category: updated_category
expect(response).to render_template :edit
end
end
I get this error:
expecting <"edit"> but rendering with <["categories/new", "layouts/application"]>
Any idea why?
Your test is calling patch :create, not patch :update, so it's running the wrong action entirely.
Related
m new to rails and rspec
I have a controller with destroy action
before_action :authorize_user, only: %i[edit update destroy]
def destroy
#question.destroy
respond_to do |format|
format.html { redirect_to questions_url, notice: 'Question was successfully destroyed.' }
format.json { head :no_content }
end
end
I have a private method
def authorize_user
redirect_to root_path if #question.user_id != current_user.id
end
This is the rspec test case I have written
describe "DELETE /destroy" do
context 'When user has signed in ' do
let!(:user) { create(:user) }
before do
sign_in(user)
end
context 'User who created the question can destroy' do
it "destroys the requested question" do
expect {
question = create(:question, user: user)
# question.user = user
# delete :destroy
delete question_url(question)
}.to change(Question, :count).by(-1)
end
end
end
end
I am getting error like this
expected `Question.count` to have changed by -1, but was changed by 0
You can't create your question in the expect block, because then you get a total of 0 count changes (0 before you create, +1 for the create, -1 for your destroy action). If you move that line outside the expect block, I suspect your test will pass.
question = create(:question, user: user)
expect { delete question_url(question) }.to change(Question, :count).by(-1)
I am learning how to test controllers in Rails. I have this action in my Posts Controller:
def update
#post = Post.new(post_params)
if #post.save
redirect_to posts_path
flash[:success] = "Your post has been updated"
else
render 'edit'
end
end
Pretty basic update action. I want to test it. This is the test I have right now:
require 'rails_helper'
RSpec.describe PostsController, type: :controller do
let!(:test_post) { Post.create(title: "testing", body: "testing") }
describe "PUT update" do
context "when valid" do
it "updates post" do
patch :update, id: test_post, post: {title: 'other', body: 'other'}
test_post.reload
expect(test_post.title).to eq('other')
end
end
end
end
This test does not pass. This is the error I get from RSpec:
1) PostsController PUT update when valid updates post
Failure/Error: expect(test_post.title).to eq('other')
expected: "other"
got: "testing"
(compared using ==)
I would appreciate some guidance. Thanks!
In your update action, you're creating a new Post, not updating an existing Post:
def update
#post = Post.new(post_params) <= here
if #post.save
redirect_to posts_path
flash[:success] = "Your post has been updated"
else
render 'edit'
end
end
You need to find your existing Post record, then update it. Which might look something more like:
def update
#post = Post.find_by(id: params[:id]) <= might need to be different depending on how you have structured your params
if #post.update_attributes(post_params)
redirect_to posts_path
flash[:success] = "Your post has been updated"
else
render 'edit'
end
end
I am getting Id missing nil error in my create controller spec. Yet I have passed ID stuff in it still facing same everytime. Here my create spec and controller file
Create Spec
describe 'POST :create' do
context 'with valid data' do
let(:valid_data) { FactoryGirl.attributes_for(:student) }
it 'redirect to show page' do
post :create, student: valid_data
expect(response).to redirect_to(student_path(assigns[:student]))
end
end
end
Student Controller
def create
#student = current_user.students.build(student_params)
respond_to do |format|
if #student.save
format.html { redirect_to #student }
format.json { render :show, status: :created, location: #student }
else
format.html { render :new }
format.json { render json: #student.errors, status: :unprocessable_entity }
end
end
end
private
def student_params
params.require(:student).permit(:Student_Prefix, :First_Name, :Middle_Name, :Last_Name, :Father_Prefix, :Father_Name, :Father_Middle_Name, :Father_Last_Name, :Mother_Prefix, :Mother_Name, :Mother_Middle_Name, :Mother_Last_Name, :user_id)
end
Error
1) StudentsController POST :create with valid data redirect to show page
Failure/Error: expect(response).to redirect_to(student_path(assigns[:student]))
ActionController::UrlGenerationError:
No route matches {:action=>"show", :controller=>"students", :id=>nil} missing required keys: [:id]
# ./spec/controllers/students_controller_spec.rb:38:in `block (4 levels) in <top (required)>'
# -e:1:in `<main>'
Your save is failing in StudentsController, so #student doesn't have an ID. You're getting the error when you try to build the path in your spec:
expect(response).to redirect_to(student_path(assigns[:student]))
assigns[:student] doesn't have an ID.
app/controllers/categories_controller.rb:
class CategoriesController < ApplicationController
before_action :set_category, only: [:show, :edit, :update, :destroy]
before_action :authenticate_user!, except: [:index, :show]
# GET /categories
# GET /categories.json
def index
#categories = Category.all
end
# GET /categories/1
# GET /categories/1.json
def show
if session[:cart] then
#cart = session[:cart]
else
#cart = {}
end
end
# GET /categories/new
def new
if current_user.admin?
#category = Category.new
end
end
# GET /categories/1/edit
def edit
if current_user.admin?
end
end
# POST /categories
# POST /categories.json
def create
if current_user.admin?
#category = Category.new(category_params)
respond_to do |format|
if #category.save
format.html { redirect_to #category, notice: 'Category was successfully created.' }
format.json { render :show, status: :created, location: #category }
else
format.html { render :new }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
end
# PATCH/PUT /categories/1
# PATCH/PUT /categories/1.json
def update
if current_user.admin?
respond_to do |format|
if #category.update(category_params)
format.html { redirect_to #category, notice: 'Category was successfully updated.' }
format.json { render :show, status: :ok, location: #category }
else
format.html { render :edit }
format.json { render json: #category.errors, status: :unprocessable_entity }
end
end
end
end
# DELETE /categories/1
# DELETE /categories/1.json
def destroy
if current_user.admin?
#category.destroy
respond_to do |format|
format.html { redirect_to categories_url, notice: 'Category was successfully destroyed.' }
format.json { head :no_content }
end
end
end
private
# Use callbacks to share common setup or constraints between actions.
def set_category
#category = Category.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def category_params
params.require(:category).permit(:name, :desc)
end
end
In the controller above I'm preventing standard users to create, update or destroy categories by checking if current_user.admin?. But it's causing some problems in the tests.
test/controllers/categories_controller.rb:
require 'test_helper'
class CategoriesControllerTest < ActionController::TestCase
setup do
#category = categories(:one)
end
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:categories)
end
test "should get new" do
get :new
assert_response :success
end
test "should create category" do
assert_difference('Category.count') do
post :create, category: { desc: #category.desc, name: #category.name }
end
assert_redirected_to category_path(assigns(:category))
end
test "should show category" do
get :show, id: #category
assert_response :success
end
test "should get edit" do
get :edit, id: #category
assert_response :success
end
test "should update category" do
patch :update, id: #category, category: { desc: #category.desc, name: #category.name }
assert_redirected_to category_path(assigns(:category))
end
test "should destroy category" do
assert_difference('Category.count', -1) do
delete :destroy, id: #category
end
assert_redirected_to categories_path
end
end
Because of the restriction, tests related with create, update or destroy are failing. I think I need to create an admin user and login on test setup. But I don't know how to do this.
I'm using Devise gem for users part of the app.
I'm running my tests with rake test:functionals. How can I simulate user create and login in my tests?
If you want to look to the whole project: https://github.com/mertyildiran/SCOR
You can use fixtures to create an admin user in the test database (you probably already have a test/fixtures/users.yml file), and Devise's Test helpers to sign in:
sign_in :user, users(:admin)
If your users are confirmable, remember to set a confirmed_at date.
Check out the Devise wiki article on testing Rails controllers.
I am learning rspec and trying to test my Account controller on create. After a user creates an account (i.e. chooses a name and a subdomain), he's redirected to a login page on his new subdomain.
My test returns NoMethodError: undefined method 'subdomain' for #<Hash:0x00000107888c88>
My account Factory is setup to generate a subdomain, so I don't see a problem with my logic. Is is just a syntax issue ?
accounts_controller.rb
class AccountsController < ApplicationController
skip_before_filter :authenticate_user!, only: [:new, :create]
def create
#account = Account.new(account_params)
respond_to do |format|
if #account.save
format.html { redirect_to new_user_session_url(subdomain: #account.subdomain, mp: 'signup' ) }
else
format.html { render action: 'new' }
format.json { render json: #account.errors, status: :unprocessable_entity }
end
end
end
end
/specs/controlles/accounts_controller_spec.rb
require 'rails_helper'
RSpec.describe AccountsController, :type => :controller do
describe "POST #create" do
context "with valid attributes" do
before :each do
#account = FactoryGirl.attributes_for(:account).merge( owner_attributes: FactoryGirl.attributes_for(:owner) )
end
it "redirects to the account subdomain login page" do
expect(post :create, account: #account).to redirect_to new_user_session_url(:subdomain => #account.subdomain)
end
end
context "with invalid attributes" do
it "does not save the new account in the database"
it "re-renders the :new template"
end
end
end
In your test, #account is a hash of account attributes
#account = FactoryGirl.attributes_for(:account).merge( owner_attributes: FactoryGirl.attributes_for(:owner) )
The above line returns a hash which you are passing as parameter while making the request
you should probably be doing account[:subdomain]
expect(post :create, account: #account).to redirect_to new_user_session_url(:subdomain => #account[:subdomain])