I'm having trouble passing my params into a nested route through rspec. I'm using Rails 5 and Rspec 3.5
My spec looks like this:
require 'rails_helper'
describe "POST /api/v1/companies/:company_id/products.json", type: :controller do
let!(:user) { create(:company_user, address: create(:address)) }
let!(:company) { create(:company, company_user: user) }
let!(:product) { create(:product) }
let!(:params) { FactoryGirl.attributes_for(:product) }
before do
#controller = Api::V1::ProductsController.new
end
context "company_user signed in" do
before do
auth_headers = user.create_new_auth_token
request.headers.merge!(auth_headers)
sign_in user
end
it 'creates a new product' do
post :create, { company_id: company.id }, { params: {product: product_params} }
expect(response.status).to eq(200)
expect(Product.count).to eq(1)
end
end
end
and in my controller my params look like this:
[1] pry(#<Api::V1::ProductsController>)> params
=> <ActionController::Parameters {"company_id"=>"1", "controller"=>"api/v1/products", "action"=>"create"} permitted: false>
Does anyone know why my product params are not being passed in?
The first Hash is the params for the test:
Try it:
post :create, { company_id: company.id, product: product_params }
Related
I am trying to write specs for a controller but my tests don't seem to be hitting the controller action.
My controller:
class CoursesController < ApplicationController
def elearning_course_removal
Rails.logger.warn("warning!")
study_group = StudyGroup.where(id: params[:study_group_id]).first
course = Course.where(id: params[:id]).first
if study_group && course
Workflow.new.remove_elearning_course(study_group, course, current_user.id)
flash[:notice] = t('study_groups.courses.remove_elearning_course.enqueue', course_name: course.name)
else
Rails.logger.error(elearning_removal_error(study_group, course))
flash[:notice] = t('study_groups.courses.remove_elearning_course.enqueue_failure')
end
redirect_to :back
end
end
My test:
require 'spec_helper'
describe CoursesController do
describe '#elearning_course_removal' do
let(:course) { FactoryBot.create(:course_with_files) }
let(:study_group) { FactoryBot.create(:study_group) }
let(:user) { FactoryBot.create(:user) }
let(:params) { {study_group_id: study_group.id, id: course.id, current_user: user} }
it 'logs' do
expect(Rails.logger).to receive(:warn)
# put :elearning_course_removal, params
controller.elearning_course_removal
end
end
Calling the route like this put :elearning_course_removal, params in the spec just fails saying that logger wasn't called. Using the second style, controller.elearning_course_removal will hit my controller method, but it's not standard, and I don't know how I would pass params in this case. Its not a routing issue, as it is identifying the controller variable correctly.
What do I need to be able to write request specs for this controller?
I think that you are not sending properly the params
RSpec.describe CoursesController do
describe "GET elearning_course_removal" do
let(:course) { FactoryBot.create(:course_with_files) }
let(:study_group) { FactoryBot.create(:study_group) }
let(:user) { FactoryBot.create(:user) }
let(:params) { {study_group_id: study_group.id, id: course.id, current_user: user} }
it "logs" do
expect(Rails.logger).to receive(:warn)
put :elearning_course_removal, params: params
end
end
you can pass params like this
params: {study_group_id: study_group.id, id: course.id, current_user: user}
params: params
or directly
put :elearning_course_removal, params: {study_group_id: study_group.id, id: course.id, current_user: user}
what you are doing is this
put :elearning_course_removal, {study_group_id: study_group.id, id: course.id, current_user: user}
params tag is missing which could be the issue
I want to test show action in my Shipment controller. To do so I've prepared fairly simple specs:
RSpec.describe ShipmentsController, type: :controller do
describe 'GET #show' do
let(:params) { { id: shipment.id, product_id: product.id } }
let!(:product) { create(:product) }
let!(:shipment) { create(:shipment, product: product) }
context 'when params are valid' do
before { get :show, params: params }
it 'return valid json' do
expect(JSON.parse(response.body)).to eq(expected_json)
end
end
end
end
ShimpentsController.rb
class ShipmentsController < ApplicationController
before_action :set_product
attr_reader :shipment
def show
#shipment = Shipment.find(params[:id])
#items = shipment&.grouped_shipment_items
end
private
def set_product
#product = Product.find(params[:product_id])
end
end
When I use postman everything went well - it returns expected json but in the RSpec test I'm getting:
response.body
=> ""
I think you need to add render_views in your controller spec file.
RSpec.describe ShipmentsController, type: :controller do
render_views
describe 'GET #show' do
let(:params) { { id: shipment.id, product_id: product.id } }
let!(:product) { create(:product) }
let!(:shipment) { create(:shipment, product: product) }
context 'when params are valid' do
before { get :show, params: params }
it 'return valid json' do
expect(JSON.parse(response.body)).to eq(expected_json)
end
end
end
end
Reference: https://rubyinrails.com/2019/04/11/rails-test-jbuilder-json-response-with-rspec/
I think you are not making a request for JSON response with rspec. You can check by putting a breakpoint in your controller action, then checking
request.format.json?
In order to ask for JSON response from an rspec test, you should add as: :json to the end of the request. The request should look like this:
get :show, params: params, as: :json
In my Rails/Grape app I created a webhook controller which receive JSON from CMS webhook. I'm just wondering how to test it in RSpec if I don't have any params (I guess I don't need it because I only receive JSON from webhook).
My webhook controller (it works well):
module Cms
class Webhook < Base
desc 'Take the CMS webhook'
http_basic do |user, password|
user == ENV['USER'] && password == ENV['PASSWORD']
end
post :receive do
params
end
end
end
I was trying to like:
describe Cms::Webhooks, type: :request do
subject(:call) { post endpoint, params: params, as: :json }
let(:endpoint) { '/api/cms/webhooks/receive' }
let(:params) do
{
some: 'some pass'
}
end
it 'returns a successful response' do
call
expect(response).to be_successful
end
end
I'm getting an error:
Failure/Error: expect(response).to be_successful
expected `#<ActionDispatch::TestResponse:0x00007f9058e43e60 #mon_data=#<Monitor:0x00007f9058e43de8>, #mon_data_..., #method=nil, #request_method=nil, #remote_ip=nil, #original_fullpath=nil, #fullpath=nil, #ip=nil>>.successful?` to return true, got false
Can you try this code?
describe Cms::Webhooks, type: :request do
subject(:call) { post endpoint, params: params, as: :son, headers: headers }
let(:endpoint) { '/api/cms/webhooks/receive' }
let(:params) do
{
some: 'some pass'
}
end
let(:headers) do
{
'HTTP_AUTHORIZATION' => ActionController::HttpAuthentication::Basic.encode_credentials('your_username', 'your_password')
}
end
it 'returns a successful response' do
call
expect(response).to be_successful
end
end
Ref https://api.rubyonrails.org/classes/ActionController/HttpAuthentication/Basic.html
I am getting the following error while testing my CommentsController with RSpec:
ActionController::UrlGenerationError:
No route matches {:action=>"create", :comment=>{:comment=>"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, :controller=>"comments"}
spec/models/comment_spec.rb
RSpec.describe CommentsController, type: :controller do
let!(:user) { create(:user) }
let!(:post1) { create(:post, user: user) }
let!(:comment) { create(:comment, user_id: user.id, post_id: post1.id) }
let!(:comment_attributes) { attributes_for(:comment) }
describe "#create" do
before do
sign_in user
end
it 'save post' do
expect do
post :create, params: { comment: comment_attributes }, session: {}
end.to change(Comment, :count).by(1)
end
it 'if post saves, redirect_to posts page' do
post :create, params: { post: comment_attributes }, session: {}
expect(response).to redirect_to(posts_path)
end
end
end
You have to update your routes.rb file every time you create a new resource (that you want to access via link), otherwise Rails don't know which controller to use with a given URL. Adding a resources :comments line in routes.rb should do it for you.
I would like to do a specific search using ransack but my test always returns all instances.
My test:
RSpec.describe UsersController, type: :controller do
describe "GET #index" do
context 'ransack search by email' do
let!(:user1) { create(:user, email: 'user1#example.com') }
let!(:user2) { create(:user, email: 'user2#example.com') }
context 'finds specific user' do
before { get :index, q: '2' }
it "should find just one user" do
expect(assigns(:users).first).to eq [user2]
end
it { should respond_with(:success) }
it { should render_template(:index) }
end
My controller:
class UsersController < ApplicationController
def index
#q ||= User.ransack(params[:q])
#users = #q.result(distinct: true)
end
end
What am I doing wrong?
The param q: should be like
q: {email_cont: '2'}