Substitution of request.formats: ["text/html"] with ["application/javascript"] - ruby-on-rails

That`s my carts_controller.rb. By default controller action add renders add.js.erb in /app/views/carts/
class CartsController < ApplicationController
def add
find_cart_and_product
#cart.products << #product
CartMailer.product_added(#product).deliver_now
end
end
and my test
describe 'POST #add' do
let(:cart_full_of){ create(:cart_with_products) }
let(:product){ create(:product) }
before do
post :add, session: { cart_id: cart_full_of.id }, params: { product_id: product.id}
end
it { expect(response.status).to eq(200) }
it { expect(response.headers["Content-Type"]).to eql("application/javascript"; charset=utf-8")}
it { is_expected.to render_template :add }
it 'should add current product into cart' do
expect(cart_full_of.products).to eq([product])
end
end
has failed with common error for all test items:
Failure/Error: post :add, session: { cart_id: cart_full_of.id }, params: { product_id: product.id}
ActionController::UnknownFormat:
CartsController#add is missing a template for this request format and variant.
request.formats: ["text/html"]
request.variant: []
I consider problem with expected requesting format, so how to force tests render with request.formats: ["application/javascript"] instead ["text/html"]?

This works for me (Rspec 3):
before :each do
request.headers["accept"] = 'application/javascript'
end

Related

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

(LikesController#create) expected #count to have changed by 1, but was changed by 0 ,Please teach me a hint

I'm biginer.
I studied Rspec.
I made an implementation that allowed me to do good on my posts.
But on the browser I do the expected move, but the test does not pass.
The destroy action goes through the test, but the create action does not pass the test.
My error is
Failure/Error: expect { post :create, format: :js, params: { post_id: post1.id, id: like.id } }.to change(Like, :count).by(1)
expected #count to have changed by 1, but was changed by 0
My code is
require 'rails_helper'
RSpec.describe LikesController, type: :controller do
let!(:user) { create(:user) }
let!(:post1) { create(:post, user: user) }
let!(:like) { create(:like, user_id: user.id, post_id: post1.id) }
describe "#create" do
before do
sign_in user
end
it "response Ajex" do
post :create, format: :js, params: { post_id: post1.id, id: like.id }
expect(response.content_type).to eq 'text/javascript'
end
it "success like function" do
expect { post :create, format: :js, params: { post_id: post1.id, id: like.id } }.to change(Like, :count).by(1)
end
end
describe "#destroy" do
before do
sign_in user
end
it "response Ajex" do
delete :destroy, format: :js, params: { post_id: post1.id, user_id: user.id, id: like.id }
expect(response.content_type).to eq 'text/javascript'
end
it "delete like function" do
expect { delete :destroy, format: :js, params: { post_id: post1.id, user_id: user.id, id: like.id } }.to change(Like, :count).by(-1)
end
end
end
likes_controller.rb
class LikesController < ApplicationController
def create
#like =
current_user.likes.find_or_create_by(post_id:params[:post_id])
#likes = Like.where(post_id: params[:post_id])
#post = Post.find(params[:post_id])
end
def destroy
like = current_user.likes.find_by(post_id: params[:post_id])
like.destroy
#likes = Like.where(post_id: params[:post_id])
#post = Post.find(params[:post_id])
end
end
I cannot solove this problem.
Please teach me a hint.
You've got an error in your code somewhere, most likely, which is why the Like count fails to increment. First, I'd try and figure out why it isn't incrementing. Since you asked for a hint, here's one way you can split out the "success like function" block:
context "valid" do
before do
post :create, format: :js, params: { post_id: post1.id, id: like.id }
end
it "success" do
# You can inject a binding.pry here if needed
expect(response.status).to eq(200)
end
it "response" do
# You can inject a `binding.pry` here if needed
# You can also inspect the `response.body` with puts if needed
expect(JSON.parse(response.body)).to include(
# You would modify this to match the shape of your response
post: a_hash_including(
like: like.id
)
)
end
end
You'll want to install pry-rails and pry-byebug gems (for inspecting).
The reason behind splitting them up is it makes it easier to determine the issue (you can have a valid response code but not the expected result, for example). This comes with some caveats (it will make for slower tests) but in this example it will make it easier to determine why your post is failing.
The snippet above should help you debug the error; once you fix it you can revert back to your previous method of checking.

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 }

Issue with apipie gem and rspec in rails 4

i'm writing the code to get my Rspec tests to pass on my api. I'm using the apipie gem to generate documentation and it seems that my tests are failing because thy are expecting a number and it's funny because this is exactly what I want to test.
The page fails when the :bpm parameter is not a number. is there any way of going around this ?
context "when is not created" do
before(:each) do
user = FactoryGirl.create :user
#invalid_lesson_attributes = { title: "California Dreamin",
bpm: "Hello"
}
request.headers['Authorization'] = user.auth_token
post :create, { user_id: user.id, lesson: #invalid_lesson_attributes }
end
it "renders an errors json" do
lesson_response = json_response
expect(lesson_response).to have_key(:errors)
end
it "renders the json errors on why the user could not be created" do
lesson_response = json_response
expect(lesson_response[:errors][:bpm]).to include "is not a number"
end
it { should respond_with 422 }
end
end
Update spec:
context "when is not updated" do
before(:each) do
patch :update, { user_id: #user.id, id: #lesson.id,
lesson: { bpm: "ten" }, format: :json }
end
it "renders an errors json" do
lesson_response = json_response
expect(lesson_response).to have_key(:errors)
end
it "renders the json errors on why the user could not be updated" do
lesson_response = json_response
expect(lesson_response[:errors][:bpm]).to include "is not a number"
end
it { should respond_with 422 }
end
in my users_controller:
api :POST, '/teachers/:user_id/lessons/', "Create lesson"
param :lesson, Hash, desc: 'Lesson information', :required => true do
param :title, String, desc: 'Title of the lesson', :required => true
param :bpm, :number, desc: 'tempo of the lesson (beats per second)', :required => true
end
error :code => 422, :desc => "Unprocessable Entity"
my error when I run my rspec tests :
Apipie::ParamInvalid: Invalid parameter 'bpm' value "Hello": Must be a number.
Adds format json to post request
post :create, { user_id: user.id, lesson: #invalid_lesson_attributes, format: :json }
That worked for me.

Where to put mocks

I'm trying to spec this action.
def get
#asset = current_user.assets.find(params[:id])
send_file #asset.uploaded_file.path, type: #asset.uploaded_file_content_type
rescue ActionController::MissingFile
redirect_to assets_url, error: 'missing file'
end
To test the send file method we mock it out.
controller.should_receive(:send_file)
However, I have no idea where to put this mock:
Here's how my spec looks:
subject { response }
let!(:user) { FactoryGirl.create(:user) }
let!(:user_2) { FactoryGirl.create(:user) }
let!(:asset) { FactoryGirl.create(:asset, user_id: user.id) }
let!(:file) { fixture_file_upload('files/eve.jpg', 'image/jpeg') }
let!(:folder) { FactoryGirl.create(:folder, user_id: user.id, parent_id: nil) }
before do
sign_in user
end
describe '#get' do
context 'when exists' do
before do
get :get, id: asset.id
end
# controller.should_receive(:send_file).with(*args) <-- I need to test that
it { should have_http_status 302 }
end
context 'when doesn\'t exist' do
before do
get :get, id: 765
end
it { should redirect_to_location '/assets'}
it { should set_flash_type_to :error }
it { should set_flash_message_to 'missing file' }
end
end
How do I test line 6. I want to keep the one line syntax if possible.
Put it in the before block
before do
controller.should_receive(:send_file)
get :get, id: asset.id
end

Resources