I'm trying to create a User in Rspec:
require "rails_helper"
RSpec.describe UsersController, type: :controller do
describe "POST #index" do
it 'should create a user' do
post :create, {name: "name1", age: 25}.to_json, format: :json
# .............
But instead I get validation errors each time: name can't be blank, age can't be blank
The UserController accepts json:
def create
#user = User.new(params1)
if #user.save
render json: #user
else
render json: #user.errors, status: :unprocessable_entity
end
end
def params1
params.permit(:id, :name, :age)
end
The parameters sent to create shouldn't be a json String but a Hash.
From the rspec documentation :
require "rails_helper"
RSpec.describe WidgetsController, :type => :controller do
describe "responds to" do
it "responds to custom formats when provided in the params" do
post :create, { :widget => { :name => "Any Name" }, :format => :json }
expect(response.content_type).to eq "application/json"
end
end
end
So your test should be :
require "rails_helper"
RSpec.describe UsersController, type: :controller do
describe "POST #create" do
it 'should create a user' do
post :create, { user: {name: "name1", age: 25}, :format => :json }
...
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
I am getting
bad argument (expected URI object or URI string)
error while running the below code at line
get :show, id: owner.id, format: :json, subdomain: 'api'
describe Api::V1::OwnersController, :type => :controller do
render_views
#before { host! "api.localhost:3000" }
let(:owner) {FactoryGirl.create(:owner)}
before(:each) do
request.host = "api.localhost:3000"
end
describe "GET #show" do
it "returns the information about an Owner on a hash" do
# TODO get this working
get :show, id: owner.id, format: :json, subdomain: 'api'
expect(response.status).to eq(200)
#owner_response = JSON.parse(response.body, symbolize_names: true)
#expect(owner_response[:email]).to eql #owner.email
end
end
end
I am adding a subdomain to render the API results here.
Try this:
get :show, params: { id: owner.id, format: :json, subdomain: 'api' }
I'm using Devise with Rspec. So I've two model called User and Article which is article belongs_to the user
When run rspec, i got an error which is say:
1) ArticlesController POST #create with valid attributes saves the article
Failure/Error: post :create, { article: valid_attributes }
#<Double "user"> received unexpected message :articles with (no args)
# ./app/controllers/articles_controller.rb:17:in `create'
# ./spec/controllers/articles_controller_spec.rb:43:in `block (4 levels) in <top (required)>'
Below is my articles_controller.rb
def new
#article ||= Article.new
render
end
def create
#article = #user.articles.new(article_params)
if #article.save
redirect_to articles_path, notice: "Well done brah! Your article has been publish"
else
render 'new'
end
end
spec/controllers/articles_controller_spec.rb
RSpec.describe ArticlesController, type: :controller do
let(:article) { FactoryGirl.create(:article) }
let (:valid_attributes) { FactoryGirl.attributes_for(:article) }
describe "POST #create" do
context "with valid attributes" do
it "saves the article" do
sign_in
post :create, { article: valid_attributes }
expect(Article.count).to eq(1)
end
end
end
spec/factories/articles.rb
FactoryGirl.define do
factory :article do
title "Article Title"
content "Article Content"
default_image "default_image"
user
category
end
end
Where is my mistake? I stuck here
UPDATED
spec/rails_helper.rb
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
config.include ControllerHelpers, :type => :controller
end
spec/support/controller_helpers.rb
module ControllerHelpers
def sign_in(user = double('user'))
if user.nil?
allow(request.env['warden']).to receive(:authenticate!).and_throw(:warden, {:scope => :user})
allow(controller).to receive(:current_user).and_return(nil)
else
allow(request.env['warden']).to receive(:authenticate!).and_return(user)
allow(controller).to receive(:current_user).and_return(user)
end
end
end
Both of the updated file above i got it from DEvise wiki - https://github.com/plataformatec/devise/wiki/How-To:-Stub-authentication-in-controller-specs
You need to use an actual database record for your user*.
RSpec.describe ArticlesController, type: :controller do
let(:article) { FactoryGirl.create(:article) }
let(:valid_attributes) { FactoryGirl.attributes_for(:article) }
let(:user) { FactoryGirl.create(:user) }
let(:valid_session) { sign_in(user) }
describe "POST #create" do
before { valid_session }
context "with valid attributes" do
it "saves the article" do
# less prone to false positives
expect do
post :create, { article: valid_attributes }
end.to change(Article, :count).by(1)
end
end
end
end
We use expect {}.to change since you can get a false positive if the database is not cleaned out properly.
Devise::TestHelpers already has a sign_in function. So get rid of your ControllerHelpers module so that your project is not linked to the Devise or Warden internals.
I'm having a perplexing problem where my controller is working fine. However, when I'm testing it with RSPEC it's returning an empty string as the response body.
Here is the controller:
class Api::UsersController < Api::ApplicationController
def show
#user = User.find(params[:id])
render 'show', status: 200
# render json: #user
end
end
And the RABL template I'm rendering:
object #user
attributes :id, :name, :email, :phone_number, :invite_token
Finally here is my spec:
require "spec_helper"
describe Api::UsersController do
it "returns user attributes" do
user = FactoryGirl.create(:user, name: "Mark", email: "foo#bar.com")
get :show, id: user.id
expect(response.status).to eq(200)
output = JSON.parse(response.body)
end
end
When I use render 'show' to render the RABL template my test fails as the response.body is an empty string. However, if I CURL to that endpoint, the body returns just fine.
When I change the controller to: render json: #user the test passes.
Can anyone tell me what's going on here?
Thanks in advance!
try to add render_views at the top of the tests
describe Api::UsersController do
render_views
it "returns user attributes" do
user = FactoryGirl.create(:user, name: "Mark", email: "foo#bar.com")
get :show, id: user.id
output = JSON.parse(response.body)
expect(response.status).to eq(200)
expect(output).to eq(expected_hash)
end
end
Possible reason: RSpec do not render views by default to speed up tests.
I'm trying to add FactoryGirl support the default scaffolded specs in my controllers and I can't seem to find the correct syntax.
Here's an example test:
describe "POST create" do
describe "with valid params" do
it "creates a new Course" do
expect {
post :create, {:course => valid_attributes}, valid_session
}.to change(Course, :count).by(1)
end
do
Which I replace by:
describe "POST create" do
describe "with valid params" do
it "creates a new Course" do
expect {
post :create, course: FactoryGirl.build(:course)
}.to change(Course, :count).by(1)
end
do
spec/factories/courses.rb
FactoryGirl.define do
factory :course do
association :provider
name "Course name"
description "course description"
end
end
app/models/course.rb
class Course < ActiveRecord::Base
validates :name, :presence => true
validates :description, :presence => true
validates :provider_id, :presence => true
has_many :terms
belongs_to :provider
end
app/controllers/courses_controller.rb
# POST /courses
# POST /courses.json
def create
#course = Course.new(course_params)
respond_to do |format|
if #course.save
format.html { redirect_to #course, notice: 'Course was successfully created.' }
format.json { render action: 'show', status: :created, location: #course }
else
format.html { render action: 'new' }
format.json { render json: #course.errors, status: :unprocessable_entity }
end
end
end
It usually fails with: "ActionController::ParameterMissing: param not found: course" does anyone have any idea?
Thanks!
Francis
Try:
describe "POST create" do
describe "with valid params" do
it "creates a new Course" do
expect {
post :create, course: FactoryGirl.attributes_for(:course, provider_id: 1)
}.to change(Course, :count).by(1)
end
end
end
Factory Girl uses attributes_for option to generate a hash of values as opposed to a Ruby object.