Not able to call a controller action in Rspec - ruby-on-rails

I have been trying to implement an RSpec for a Controller called "Estimate controller" to test whether my mailing functionality (sending estimate) working properly or not. But I'm not able to call the controller action from my RSpec. I need to set some values (to, subject, message, cc, current_user, attachments) in a hash and send that hash to Estimate controller.Here is what I tried..
estimates_controller_spec.rb
describe "post 'send_estimate'" do
it "should send estimate " do
#estimate = Fabricate(:estimate, id: Faker::Number.number(10), validity: "12/12/2014", total_value: 1222.00, user_id:#user.id, project_id: #project_id)
est_params = {
to: "rspec#rails.com",
subject: "Estimate",
message: "Check out the Estiamte details",
cc: "respec#rails.com",
current_user: #user,
attachments: ""
}
expect{
post :send_estimate, estimate: est_params
}.to change { ActionMailer::Base.deliveries.count }.by(1)
end
end
estimates_controller.rb
def send_estimate
respond_to do |format|
if #estimate.send_email(params[:to], params[:subject], params[:message], params[:cc], current_user, params[:attachments])
#estimate.create_activity :send_estimate, owner: current_user, recipient: #estimate.project
format.html { redirect_to lead_path(#estimate.project), notice: "Email sent Successfully"}
format.json { head :no_content, status: :ok}
else
format.json { render json: #estimate.errors }
format.html { redirect_to contacts_path, notice: 'Something went wrong' }
end
end
end

Related

Rspec test fails while rendering

For my user controller, while running the test cases I am facing render issue. It is redirecting to http://test.host/sign_in instead of rendering new.
Controller code
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
UserMailer.registration_confirmation(#user).deliver_now
session[:user_id] = #user.id
format.html { redirect_to sign_in_path, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
spec/users_controller_spec.rb
describe '#create' do
it 'User created' do
new_user = FactoryBot.build :user
post :create, params: {
user: {
id: new_user.id,
firstname: new_user.firstname,
email: new_user.email,
password: "s",
password_confirmation:"s"
}
}
expect(response).to render_template("new")
end
end
While running this test case I am facing this error!
Error
Failures:
1) UsersController controller test cases #create User created
Failure/Error: expect(response).to render_template("new")
expecting <"new"> but was a redirect to <http://test.host/sign_in>
# ./spec/controllers/users_controller_spec.rb:30:in `block (4 levels) in <top (required)>'
How do I resolve this?
According to your controller code, you redirect to sign_in when the save is successful :
format.html { redirect_to sign_in_path, notice: 'User was successfully created.' }
Your failing test is saying :
expecting <"new"> but was a redirect to <http://test.host/sign_in>
It comes from expect(response).to render_template("new"). You might want to change this line to expect(subject).to redirect_to(sign_in_path).
The behaviour render_template("new") might be relevant when #user.save is false

Trouble testing for an error thrown from AASM gem

I'm having trouble testing for a thrown AASM error.
Here is my controller method:
# controllers/jobs_controller.rb
def change_state
respond_to do |format|
if #job.close && #job.save
format.html { redirect_to #job, notice: 'Job has been closed.' }
format.json { render :show, status: :ok, location: #job }
else
format.html { render :show, notice: 'Job could not be closed.' }
format.json { render json: #job.errors, status: :unprocessable_entity }
end
end
end
My spec looks like this:
# spec/controllers/jobs_controller_spec.rb
describe "POST #change_state" do
it "cannot transition job from closed" do
job.aasm_state = "closed"
job.save!
post :change_state, params: {id: job.hash_id, user_id: user.id}
expect { response }.to raise_error(AASM::InvalidTransition)
end
end
The test fails (with the expected/desired failure):
Failure/Error: if #job.close && #job.save
AASM::InvalidTransition:Event 'close' cannot transition from 'closed'.
I'm just unable to figure out the right syntax to pass the test. I've tried a few variations of the expect line but can't seem to piece it together.
Any guidance is appreciated.
The exception is happening before the expect statement. Try it:
expect {
post(:change_state, params: { id: job.hash_id, user_id: user.id })
}.to(
raise_error(AASM::InvalidTransition)
)

RSpec request example failing

I'm trying to do a really simple request spec for testing my API methods in my application. Right now I'm getting 302 message when I should be getting 200 with this test.
The spec:
require 'spec_helper'
describe UsersController do
describe "#create" do
it "creates a new user " do
post '/users', user: FactoryGirl.attributes_for(:user)
expect(response.status).to eq 200
end
end
end
The factory:
FactoryGirl.define do
factory :user do
sequence(:name) { |n| "Person #{n}" }
sequence(:username) { |n| "Person#{n}" }
sequence(:email) { |n| "person_#{n}#example.com"}
password "foobar"
password_confirmation "foobar"
end
end
The controller method:
def create
#user = User.new(user_params)
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'User was successfully created.' }
format.json { render :show, status: :created, location: #user }
else
format.html { render :new }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
What am I missing?
So you need to make the asynchronous post request, it should be something like below,
it "creates a new user " do
xhr :post, '/users', user: FactoryGirl.attributes_for(:user)
expect(response.status).to eq 200
end
Try this, it might work
To solve the issue I need to add the ACCEPT header to my request, like so:
post "/users", { user: #user } , { accept: 'application/json' }
Doing this fixed the issue which was the server not interpreting the request as expecting json in return.

How would I test a param is getting modified in a RSpec controller test?

I am setting a user through modifying the params instead of creating a hidden_field in the form. As far as I understand, this is a more secure way of handling mass-assignment.
def update
#exercise = Exercise.find(params[:id])
#this is the important part
if params[:exercise][:log_entries_attributes].present?
params[:exercise][:log_entries_attributes].each do |value|
value[1].merge!(:user_id => current_user.id)
end
end
#end the important part
respond_to do |format|
if #exercise.update_attributes(params[:exercise])
format.html { redirect_to_back_or_default #exercise, notice: "Exercise was successfully updated." }
format.mobile { redirect_to #exercise, notice: 'Exercise was successfully updated.' }
format.json { head :ok }
else
format.html { render action: "edit" }
format.mobile { redirect_to #exercise, notice: "#{#exercise.errors.full_messages.to_sentence}" }
format.json { render json: #exercise.errors, status: :unprocessable_entity }
end
end
end
In my spec I have the following:
describe "with log_entry_attributes" do
it "updates log_entries_attributes and sets user" do
exercise = FactoryGirl.create(:exercise)
log_entry = FactoryGirl.build(:log_entry)
exercise.log_entries << log_entry
exercise.save
controller.stub(:current_user).and_return(#user)
put :update, :id => exercise.id, :exercise => FactoryGirl.build(:exercise, "log_entries_attributes" => {":0" => {"reps" => "5", "weight" => "5"}}).attributes.symbolize_keys
assigns(:exercise).log_entries.first.user.should eq(#user)
end
end
I get undefined method user for nil:NilClass. I think I know why I get undefined method user. There's just no way to get the association through assigns. I'm not sure how to test that the user_id is being set properly through the current_user. Any help?
Work with mocked object:
exercise = double "exercise"
Exercise.should_receive(:find).and_return(exercise)
and test with:
exercise.should_receive(:update_attributes).with(correct_params)

How to render view first and send email in background with Ruby on Rails and ActionMailer

My app has a simple signup where the user types in his/her email address and POSTs the request. The request is then sent to my server using AJAX, an email is sent to the user's email using ActionMailer, and a thank you message is rendered using jQuery. With the code I have currently, the thank-you message is rendered only AFTER the email is sent, so it takes some time for the thank-you message to show. However, I'd like the thank-you message to be rendered first, and the email to be sent to the user in the background, so that the user can immediately know that his/her email was saved. Is there a way to process email in the background with Rails?
Below is my current code.
In users_controller.rb
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'Thank you for signing up!' }
format.js
format.json { render json: #user, status: :created, location: #user }
Notifier.email_saved(#user).deliver
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
In mailers/notifier.rb
class Notifier < ActionMailer::Base
default from: "First Last <my#email.com>"
def email_saved(user)
#email = user.email
mail to: #email, subject: 'Auto-Response: Thank you for signing up'
end
end
In users/create.js.erb
$("<div class='alert alert-success'>Thank you for showing your interest! A confirmation email will be sent to you shortly.</div>").insertAfter("#notice");
If you want to send mail only, you should use better "Resque" or "Delayed Job" than "Ajax".
#271 Resque - RailsCasts http://railscasts.com/episodes/271-resque
Delayed Job (DJ) | Heroku Dev Center https://devcenter.heroku.com/articles/delayed-job
But if you want to send mail using Ajax, please use below snippets as a reference.
#app/controllers/users_controller.rb
def create
#user = User.new(params[:user])
respond_to do |format|
if #user.save
format.html { redirect_to #user, notice: 'Thank you for signing up!', sign_up_flag: 1 }
format.js
format.json { render json: #user, status: :created, location: #user }
else
format.html { render action: "new" }
format.json { render json: #user.errors, status: :unprocessable_entity }
end
end
end
def send_mail(user_id)
begin
user = User.find(user_id)
Notifier.sign_up_mail(user.email).deliver
render :nothing => true, :status => 200
rescue
render :nothing => true, :status => 500
end
end
#app/mailers/notifier.rb
class Notifier < ActionMailer::Base
default from: "First Last <my#email.com>"
def sign_up_mail(email)
mail to: email, subject: 'Auto-Response: Thank you for signing up'
end
end
#app/views/???.html.erb
<% if #sign_up_flag == 1 %>
$(document).ready(function(){
$.ajax({
type: "POST",
url: "/sendmail",
data: "",
success : function(){},
error : function() {}
});
});
<% end %>
#config/routes.rb
post '/sendmail' => 'users#send_mail'
Thanks.

Resources