Rspec testing ransack always returning all instances - ruby-on-rails

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'}

Related

How to make request specs for rails controller - request not hitting controller method

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

RSpec returns empty string in a fairly simple get request

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

Rspec nested controller test not passing params into my controller

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 }

RSpec Helper Parameters Issue

I'm trying to test the following code:
module ApplicationHelper
def current_book
Book.find(params[:id])
end
end
using the following test with RSpec:
RSpec.describe ApplicationHelper, :type => :helper do
describe "#current_book" do
book_1 = create(:book)
params = {}
params[:id] = book_1.id
expect(helper.current_book).to eq(book_1)
end
end
But for some reason the params[:id] parameter isn't being passed in properly. Any suggestions with this?
You need to stub the params:
RSpec.describe ApplicationHelper, type: :helper do
describe "#current_book" do
let(:first_book) { create(:book) }
before(:all) { helper.stub!(:params).and_return(id: 1) }
it "returns a book with a matching id" do
expect(helper.current_book).to eq(first_book)
end
end
end
Here another way of stubbing params. I think this requires rspec 3 can't remember for sure.
context 'path is a route method' do
before { allow(helper).to receive(:params).and_return(order_by: { updated_at: :desc }) }
subject { helper.sortable_link_to('Created At', order_by: :created_at) }
it { is_expected.to match /comments/ }
it { is_expected.to match /\?order_by/}
it { is_expected.to match /\?order_by%5Bupdated_at%5D=asc/}
end

rspec expects all :resources to equal resource

I'm new to RSpec, I wonder why I didn't pass this test
before(:each) { get :index }
it "assigns all favorites as #favorites" do
favorite = FactoryGirl.create(:favorite)
expect(assigns(:favorites)).to eq([favorite])
end
It says
1) FavoritesController GET index assigns all favorites as #favorites
Failure/Error: expect(assigns(:favorites)).to eq([favorite])
expected: [#<Favorite id: 1, patient_id: 6, doctor_id: 5>]
got: #<ActiveRecord::Relation []>
(compared using ==)
Diff:
## -1,2 +1,2
-[#<Favorite:0x000000058a5ca0 id: 1, patient_id: 6, doctor_id: 5>]
+[]
It seems assigns(:favorites) got empty. I have tried another approach as well
def valid_attributes
doctor = FactoryGirl.create(:doctor)
patient = FactoryGirl.create(:patient)
FactoryGirl.attributes_for(:favorite, doctor_id: doctor.id, patient_id: patient.id)
end
it "assigns all favorites as #favorites" do
favorite = Favorite.create! valid_attributes
expect(assigns(:favorites)).to eq([favorite])
end
And it got the same error. Any inputs would be helpful for me and I'd like to ask if there is any way to simplify it.
Update
app/controllers/favorite_controller.rb
class FavoritesController < ApplicationController
before_action :set_favorite, only: [:destroy]
before_action :authenticate_user!
def index
#favorites = Favorite.where(:patient_id => current_user.id).order(id: :asc)
end
end
spec/controllers/favorite_controller_spec.rb
require 'spec_helper'
describe FavoritesController, type: :controller do
login_patient
describe "GET index" do
let!(:favorite) { FactoryGirl.create(:favorite) }
before { get :index }
it { expect(response).to render_template(:index) }
it { expect(response).to be_success }
it { expect(response).to have_http_status(200) }
it "blocks unauthenticated access", :skip_before do
expect(response).to redirect_to(new_user_session_path)
end
it "assigns all favorites as #favorites" do
expect(assigns(:favorites).to_a).to eq([favorite])
end
end
end
spec/support/controller_helpers.rb
module ControllerHelpers
def login_patient
before :each do |example|
unless example.metadata[:skip_before]
#request.env["devise.mapping"] = Devise.mappings[:user]
#patient = FactoryGirl.create(:patient)
sign_in :user, #patient
end
end
end
end
You are creating the records after you send the request so by the time the request finishes, the record you just created isn't included in the list of favorites. Change your test code to the following
let!(:favorite) { FactoryGirl.create(:favorite) }
before { get :index }
it "assigns all favorites as #favorites" do
expect(assigns(:favorites)).to eq([favorite])
end
This will probably still fail because assigns(:favorites) is an ActiveRecord::Relation object so you have to call to_a
expect(assigns(:favorites).to_a).to eq([favorite])
UPDATE:
Since the favorite is being filtered by patient, you have to make sure that the created favorite in the test belongs to the patient. You can do that by changing the favorite to
let!(:favorite) { FactoryGirl.create(:favorite, patient: #patient)
Try to create the records before the request:
let!(:favorite) { FactoryGirl.create(:favorite) }
before(:each) { get :index }
it "assigns all favorites as #favorites" do
expect(assigns(:favorites).to_a).to eq([favorite])
end

Resources