I have a question concerning a functional test in rails.
For the front section, the actions are only index and show
#app/controller/themes_controller_rb
class ThemesController < ApplicationController
def index
#themes = Theme.active
end
def show
#theme = Theme.find(params[:id])
end
def new
end
end
and the test
#test/integration/theme_controller_test.rb
require 'test_helper'
class ThemesControllerTest < ActionController::TestCase
def setup
#theme = create(:theme)
end
test "should assign variable on index" do
get :index
assert_response :success
assert_not_nil assigns(:themes)
end
test "should show a theme" do
get :show, {'id' => #theme}
assert_response :success
assert_not_nil assigns(:theme)
end
end
No problem so far
For the admin section, all the CRUD actions exists so again index and show
#app/controllers/admin/themes_controller.rb
class Admin::ThemesController < Admin::AdminController
layout 'admin/admin'
before_action :admin_user
def index
#themes = Theme.all
end
def show
#theme = Theme.find(params[:id])
end
end
and the tests are the same
#test/controllers/admin/theme_controller_test.rb
require 'test_helper'
class Admin::ThemesControllerTest < ActionController::TestCase
def setup
#theme = create(:theme)
end
test "should assign variable on index" do
get :index
assert_response :success
assert_not_nil assigns(:themes)
end
test "should show a theme" do
get :show, {'id' => #theme}
assert_response :success
assert_not_nil assigns(:theme)
end
end
but for those latest tests, I have a 302 response instead of succes
FAIL["test_should_assign_variable_on_index", Admin::ThemesControllerTest, 2016-03-16 06:50:16 +0000]
test_should_assign_variable_on_index#Admin::ThemesControllerTest (1458111016.61s)
Expected response to be a <success>, but was <302>
test/controllers/admin/themes_controller_test.rb:11:in `block in <class:ThemesControllerTest>'
FAIL["test_should_show_a_theme", Admin::ThemesControllerTest, 2016-03-16 06:50:16 +0000]
test_should_show_a_theme#Admin::ThemesControllerTest (1458111016.62s)
Expected response to be a <success>, but was <302>
test/controllers/admin/themes_controller_test.rb:18:in `block in <class:ThemesControllerTest>'
What do I do wrong ? Thanks for help :)
Related
I'm new to rails api rspec and somehow I cannot make the test work. Can someone provide some inputs in the tests? The models and controllers are more like a pseudocode. I appreciate it. Thank you.
# routes.rb
Rails.application.routes.draw do
resources :users, :only [:create]
end
# app/model/user.rb
class User < ApplicationRecord
validates_uniqueness_of :name
end
# app/controllers/users_controller.rb
def create
#user = User.new(user_params)
if #user.save
head 200
else
render json: { error: 'Failed', status: 400}, status: 400
end
end
def user_params
params.require(:user).permit(:name)
end
# RSpec Test
require 'rails_helper'
RSpec.describe UsersController do
describe '#create' do
context 'the parameter "user[name]"" is blank' do
it 'creates new user' do
#Test Here
end
it 'renders empty response' do
#Test Here
end
it 'renders response with status 200' do
#Test Here
end
end
end
end
spec/models/user_spec.rb make sure you install gem shoulda-matchers and factory_bot_rails
require 'rails_helper'
RSpec.describe User, type: :model do
let(:user) { create(:user) }
describe "validation" do
it { should validate_uniqueness_of(:name) }
end
end
spec/controllers/users_controller_spec.rb
require 'rails_helper'
RSpec.describe UserssController, type: :controller do
describe "POST /users" do
it "when create user successfully return status 200" do
post :create, params: { name: "name" }
expect(response.status).to eq 200
end
it "when create user errors return status 400" do
post :create, params: { name: "name duplicate" }
expect(response.status).to eq 400
end
end
end
I hope it helps for you
so i've been trying to make a basic response test - with 200 and 403. I'm not sure i need to add anything else ..
accounts_spec.rb
RSpec.describe Api::V1::AccountsController, :type => :controller do
describe "GET index no account" do
it "has a 403 status code" do
get :index
expect(response.status).to eq(403)
end
end
describe "GET index with account" do
login_user
it "has a 200 status code" do
get :index
expect(response.status).to eq(200)
end
end
end
Accounts Controller #index
def index
#show user details
raise if not current_user
render json: { :user => current_user.as_json(:except=>[:created_at, :updated_at, :authorization_token, :provider, :uid, :id])}
rescue
render nothing: true, status: 403
end
I keep getting
1)Api::V1::AccountsController GET index with account has a 200 status code
expected: 200
got: 403
Any thoughts on where i'm doing it wrong ?
UPDATE
module ControllerMacros
def login_user
before(:each) do
#request.env["devise.mapping"] = Devise.mappings[:user]
user = FactoryGirl.create(:user)
sign_in :user, user
end
end
end
Much cleaner implementation
class SomeController < ApplicationController
before_action :authenticate
skip_before_action :verify_authenticity_token, if: :json_request?
def index
render json: { user: current_user...
end
protected
def json_request?
request.format.json?
end
def authenticate
head :unauthorized unless current_user
end
end
I also recommend in using ActiveModel Serializer https://github.com/rails-api/active_model_serializers. This will separate logic of render json and oy will have a separate class under serializer that defines the json output. So your render method will look like this:
render json: current_user, status: :ok
app/serializers/user.rb
class UserSerializer < ActiveModel::Serializer
attribute :id, :email #list your attributes for json output
end
If you want to test json response in your rspec what I find best is testing against json schema like this library https://github.com/sharethrough/json-schema-rspec.
Hope it helps
post_controller file
class PostsController < ActionController::Base
before_action :authenticate_user!
def index
#post = current_user.posts.paginate(page: params[:page], per_page: 5)
respond_to do |format|
format.html
format.json { render json: #post }
end
end
def new
#post = Post.new
end
def create
#post = current_user.posts.build(post_param)
if #post.save
redirect_to action: 'index'
else
render 'new'
end
post_controller_test
require 'test_helper'
class PostsControllerTest < ActionController::TestCase
include Devise::TestHelpers
def setup
#user = users(:Bob)
#post = Post.new
end #passed
test 'logged in should get show' do
sign_in #user
get :index
assert_response :success
end #passed
test 'not authenticated should get redirect' do
get :index
assert_response :redirect
end #passed
test 'should get index' do
get :index
assert_response :success
assert_not_nil assigns(:posts)
end #failing
test "should destroy post" do
assert_difference('Post.count', -1) do
delete :destroy, id: #post
end
assert_redirected_to posts_path
end #failing
...
devise is setup and working fine but why I am getting 302 error in last two cases. Is it because I am not passing #user parameters to it? I did but it was still throwing the same error. I also checked out my routes file which is fine because post_controller is working fine in development mode.
What I am doing wrong here?
Edit-1
I tried to create test cases for create method
def setup
#user = users(:bob)
#p = posts(:one)
#post = Post.new
end
test 'should create post' do
sign_in #user
assert_difference('Post.count') do
post :create, post: { name: #p.name, value: #p.value}
end
end
I am getting ActionController::ParameterMissing: param is missing or the value is empty: post while in my controller class I do have
params.require(:post).permit(:name, :value, :user_id)
I also have all parameters in my .yml file i.e.
one:
name: 2
value: 3
It looks like you need to sign in before trying the index action. You're also testing the wrong instance variable name. You're testing #posts, but you've defined #post in the controller. Try this test instead:
test 'should get index' do
sign_in #user
get :index
assert_response :success
assert_not_nil assigns(:post)
end
I have a before_action filter and want to test that the index action is only executed if the user is logged in. Simply put, i don't know how to do this. I'm using my own simple authentication and i know i could use CanCan or similar but for my own learning i'm doing it the hard way!
ApplicationController.rb
helper_method :logged_in
helper_method :current_user
def current_user
#current_user ||= User.find_by_id(session[:current_user]) if session[:current_user]
end
def logged_in
unless current_user
redirect_to root_path
end
end
ActivitiesController.rb
before_action :logged_in
def index
#activities = Activity.all.where(user_id: #current_user)
end
Activities_Controller_spec.rb
require 'rails_helper'
RSpec.describe ActivitiesController, :type => :controller do
describe "GET index" do
before(:each) do
#activity = FactoryGirl.create(:activity)
session[:current_user] = #activity.user_id
#current_user = User.find_by_id(session[:current_user]) if session[:current_user]
end
it "shows all activities for signed in user" do
get :index, {user_id: #activity.user_id}
expect(response).to redirect_to user_activities_path
end
end
end
activities.rb(Factory)
FactoryGirl.define do
factory :activity do
association :user
title { Faker::App.name }
activity_begin { Faker::Date.forward(10) }
activity_end { Faker::Date.forward(24) }
end
end
I'm getting the following error:
Failure/Error: expect(response).to redirect_to user_activities_path
Expected response to be a redirect to <http://test.host/users/1/activities> but was a redirect to <http://test.host/>.
Expected "http://test.host/users/1/activities" to be === "http://test.host/".
After long discussion I think tests should be smth like this (it is not tested :) )
require 'rails_helper'
RSpec.describe ActivitiesController, :type => :controller do
describe "GET index" do
before(:each) do
#activity = FactoryGirl.create(:activity)
end
context 'when user is logged' do
before(:each) do
session[:current_user] = #activity.user_id
end
it "shows all activities for signed in user" do
get :index, {user_id: #activity.user_id}
expect(response).to be_success
end
end
context 'when user is anonymous' do
it "redirects user to root path" do
get :index, {user_id: #activity.user_id}
expect(response).to redirect_to root_path
end
end
end
end
My spec is like so:
describe SomeController do
before(:each) do
#request.env["HTTP_ACCEPT"] = 'application/vnd.apple.mpegurl'
end
describe 'GET #index' do
it "returns response" do
get 'index', format: :m3u8
puts response.code # prints 406
response.should be_success # fails
end
end
end
The controller:
class SomeController < AuthenticatedController
def index
Mime::Type.register "application/vnd.apple.mpegurl", :m3u8
# do some stuff
respond_to do |format|
format.m3u8 { render :m3u8 => #some_variable.html_safe }
end
end
What am I missing to get it to respond with status 200? Right now, the status returned is 406. Thanks.
Drop the #.
before(:each) do
request.env["HTTP_ACCEPT"] = 'application/vnd.apple.mpegurl'
end