Can't figure out what's causing my tests to fail - ruby-on-rails

I'm new to rails and I built an app without doing TDD but am now going back and trying to pass all the tests. I've passed most of them but there are a few left relating to the same issue that I can't figure out. The app functions correctly as well, I just can't pass these tests.
The tests fail and provide this:
1) ProductsController POST create with valid params assigns a newly created product as #product
Failure/Error: post :create, {:product => valid_attributes}, valid_session
Paperclip::AdapterRegistry::NoHandlerError:
No handler found for "#<File:0x007fc6d17b28f8>"
# ./app/controllers/products_controller.rb:43:in `new'
# ./app/controllers/products_controller.rb:43:in `create'
# ./spec/controllers/products_controller_spec.rb:86:in `block (4 levels) in <top (required)>'
2) ProductsController POST create with valid params creates a new Product
Failure/Error: post :create, {:product => valid_attributes}, valid_session
Paperclip::AdapterRegistry::NoHandlerError:
No handler found for "#<File:0x007fc6d1757cf0>"
# ./app/controllers/products_controller.rb:43:in `new'
# ./app/controllers/products_controller.rb:43:in `create'
# ./spec/controllers/products_controller_spec.rb:81:in `block (5 levels) in <top (required)>'
# ./spec/controllers/products_controller_spec.rb:80:in `block (4 levels) in <top (required)>'
3) ProductsController POST create with valid params redirects to the created product
Failure/Error: post :create, {:product => valid_attributes}, valid_session
Paperclip::AdapterRegistry::NoHandlerError:
No handler found for "#<File:0x007fc6d36b3dd8>"
# ./app/controllers/products_controller.rb:43:in `new'
# ./app/controllers/products_controller.rb:43:in `create'
# ./spec/controllers/products_controller_spec.rb:92:in `block (4 levels) in <top (required)>'
The "create" method in my controller:
def create
#product = Product.new(params[:product])
respond_to do |format|
if #product.save
format.html { redirect_to admin_path, notice: 'Product was successfully created.' }
format.json { render json: #product, status: :created, location: #product }
else
format.html { render action: "new" }
format.json { render json: #product.errors, status: :unprocessable_entity }
end
end
end
My Model:
class Product < ActiveRecord::Base
attr_accessible :designed, :features, :photo, :manufactured, :name, :case_study
has_attached_file :photo, {
:styles => {
:thumb => "x50>",
:small => "x150>",
:detail => "x600>"
}
}.merge(PAPERCLIP_STORAGE_OPTIONS)
validates_attachment_presence :photo
validates_attachment_size :photo, :less_than => 5.megabytes
validates_attachment_content_type :photo, :content_type => ['image/jpeg', 'image/png']
end
My test:
before(:each) do
#image = File.new(Rails.root + 'spec/fixtures/images/test.png')
end
def valid_attributes
{ "photo" => #image }
end
describe "POST create" do
describe "with valid params" do
it "creates a new Product" do
expect {
post :create, {:product => valid_attributes}, valid_session
}.to change(Product, :count).by(1)
end
it "assigns a newly created product as #product" do
post :create, {:product => valid_attributes}, valid_session
assigns(:product).should be_a(Product)
assigns(:product).should be_persisted
end
it "redirects to the created product" do
post :create, {:product => valid_attributes}, valid_session
response.should redirect_to(admin_path)
end
end
end

If you're using Rails 3.2, try sending an UploadedFile instead of File in your tests. UploadedFile takes a filename, and a content-type in its initializer.
before(:each) do
#image = Rack::Test::UploadedFile.new(Rails.root.join('spec/fixtures/images/test.png'), 'image/png')
end
You might have to include Rack::Test::Methods in your test or test helper.

You can also use fixture_file_upload as a shortcut to Rack::Test::UploadedFile.new like this:
post :create, product: { photo: fixture_file_upload('spec/fixtures/images/test.png', 'image/png') }

Have you added the Paperclip attachment to your databases -- eg created and run migrations? Including the test database?

Related

Rspec testing No Route Matches ActionController::UrlGenerationError

I'm trying to wrap my head about Rspec and Controller tests, more specifically a JSON request. In this case, I'm trying to hit the v1_devices_path route:
routes.rb
v1_device_scans POST /v1/devices/:device_serial_number/scans(.:format) v1/scans#create
v1_device GET /v1/devices/:serial_number(.:format) v1/devices#show
PATCH /v1/devices/:serial_number(.:format) v1/devices#update
PUT /v1/devices/:serial_number(.:format) v1/devices#update
And my controller:
controllers/v1/devices_controller.rb
class V1::DevicesController < ApplicationController
before_action :set_device, only: [:show, :update]
respond_to :json
def show
#device = Device.find_by(serial_number: params[:serial_number])
render :json => #device.as_json
end
def update
if #device.update(device_params)
render json: #device, status: :ok, location: #device
else
render json: #device.errors, status: :unprocessable_entity
end
end
private
def set_device
#device = Device.find_by!(serial_number: params[:serial_number])
end
def device_params
params.require(:device).permit(
:serial_number,
:name,
:diagnostic_checkin_status,
:diagnostic_dns,
:diagnostic_ping,
:assigned_internal_ip,
:assigned_external_ip,
:assigned_gateway_ip,
:version,
:timezone,
:task_id,
:scan_status,
:scan_progress
)
end
end
As of right now my test is super simple... just want to make sure I get some results back:
spec/controllers/v1/devices_controller_spec.rb
require 'rails_helper'
RSpec.describe V1::DevicesController, type: :controller do
it "shows device info" do
device = FactoryGirl.create(:device)
get v1_device_path(device.serial_number), :format => :json
expect(response.status).to be(200)
end
end
After some tweaking, I've gotten to the point where it looks like my url is being created correctly, but I'm still getting the no route matches error:
1) V1::DevicesController shows device info
Failure/Error: get v1_device_path(device.serial_number), :format => :json
ActionController::UrlGenerationError:
No route matches {:action=>"/v1/devices/41442305171c430ab253ba1ad95c5c61", :controller=>"v1/devices", :format=>:json}
# /usr/local/bundle/gems/rails-controller-testing-1.0.2/lib/rails/controller/testing/template_assertions.rb:61:in `process'
# /usr/local/bundle/gems/devise-4.3.0/lib/devise/test/controller_helpers.rb:33:in `block in process'
# /usr/local/bundle/gems/devise-4.3.0/lib/devise/test/controller_helpers.rb:100:in `catch'
# /usr/local/bundle/gems/devise-4.3.0/lib/devise/test/controller_helpers.rb:100:in `_catch_warden'
# /usr/local/bundle/gems/devise-4.3.0/lib/devise/test/controller_helpers.rb:33:in `process'
# /usr/local/bundle/gems/rails-controller-testing-1.0.2/lib/rails/controller/testing/integration.rb:12:in `block (2 levels) in <module:Integration>'
# ./spec/controllers/v1/devices_controller_spec.rb:11:in `block (2 levels) in <top (required)>'
What am I doing wrong?
This is another solution to not change type into request. This error shows because of adding serial_number parameter in show devise route, you can add serial_number in your get url.
RSpec.describe V1::DevicesController, type: :controller do
it "shows device info" do
device = FactoryGirl.create(:device)
get :show, params: { serial_number: device.serial_number }, :format => :json
expect(response.status).to be(200)
end
end
I hope this help you.
Alright, starting with #sebastián's comment, I changed the spec to:
require 'rails_helper'
RSpec.describe V1::DevicesController, type: :request do
it "shows device info" do
headers = {
"ACCEPT" => "application/json", # This is what Rails 4 accepts
}
device = FactoryGirl.create(:device)
get v1_device_path(device.serial_number), :headers => headers
expect(response.content_type).to eq("application/json")
end
end
And my test passes now.

Rspec failing on API create action

Rspec keeps failing on this create action, i.e. the event is a Nil object when the test runs. The other tests passes on all of my user and user token authentication secttions fine. It's loading the FFaker/Factory-Girl data properly. Can't seem to find an answer anywhere.
events_controller_rspec.rb
describe "POST #create" do
context "when is successfully created" do
before(:each) do
user = FactoryGirl.create(:user)
#event_attributes = FactoryGirl.attributes_for(:event)
api_authorization_header user.auth_token
post :create, { user_id: user.id, event: #event_attributes }, format: :json
end
it "renders the JSON representation for the event record just created" do
event_response = json_response[:event]
expect(event_response[:name]).to eql #event_attributes[:name]
end
it { should respond_with 201 }
end
events_controller.rb
def create
event = current_user.events.build(event_params)
if event.save
render json: event, status: 201, location: [:api, event]
else
render json: { errors: event.errors }, status: 422
end
end
private
def event_params
params.require(:event).permit(:name, :user_id)
end
end
app/concerns/authenticatable.rb
module Authenticable
# Devise methods overwrites
def current_user
#current_user ||= User.find_by(auth_token: request.headers['Authorization'])
end
end
Rspec Results
Failures:
1) Api::V1::EventsController POST #create when is successfully created renders the JSON representation for the event record just created
Failure/Error: expect(event_response[:name]).to eql #event_attributes[:name]
NoMethodError:
undefined method `[]' for nil:NilClass
# ./spec/controllers/api/v1/events_controller_spec.rb:75:in `block (4 levels) in <top (required)>'
2) Api::V1::EventsController POST #create when is successfully created should respond with 201
Failure/Error: it { should respond_with 201 }
Expected response to be a 201, but was 422
# ./spec/controllers/api/v1/events_controller_spec.rb:78:in `block (4 levels) in <top (required)>'
Your event_params method tells in params.require(:event).permit(:name, :user_id) that the user_id needs to be part of the event attributes.
Change:
post :create, { user_id: user.id, event: #event_attributes }, format: :json
to
post :create, { event: #event_attributes.merge(user_id: user.id) }, format: :json

Rspec user controller - NoMethodError: undefined method 'user_url'

I'm now making Rspec test for users_controller.rb. However I'm in trouble the error NoMethodError: undefined method 'user_url' as follow.
FF
Failures:
1) UsersController PUT update user update does not succeed
Failure/Error: put :update, {:id => user.to_param}, valid_session, :user_route => user
NoMethodError:
undefined method `user_url' for #<UsersController:0x52e40e0>
# ./app/controllers/users_controller.rb:21:in `block (2 levels) in update'
# ./app/controllers/users_controller.rb:18:in `update'
# ./spec/controllers/users_controller_spec.rb:64:in `block (3 levels) in <top (required)>'
2) UsersController PUT update user update succeeds
Failure/Error: put :update, {:id => user.to_param}, valid_session, :user_route => user
NoMethodError:
undefined method `user_url' for #<UsersController:0x53bc560>
# ./app/controllers/users_controller.rb:21:in `block (2 levels) in update'
# ./app/controllers/users_controller.rb:18:in `update'
# ./spec/controllers/users_controller_spec.rb:58:in `block (3 levels) in <top (required)>'
Finished in 0.679 seconds
2 examples, 2 failures
Failed examples:
rspec ./spec/controllers/users_controller_spec.rb:61 # UsersController PUT update user update does not succeed
rspec ./spec/controllers/users_controller_spec.rb:56 # UsersController PUT update user update succeeds
Randomized with seed 33412
users_controller.rb
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #user }
end
end
def edit
#user = User.find(params[:id])
end
def update
#user = User.find(params[:id])
respond_to do |format|
if #user.update_attributes(params[:user])
format.html { redirect_to #user, notice: 'User was successfully updated.' }
format.json { head :no_content }
else
format.html { render action: "user#edit" }
format.json { render json: #idea.errors, status: :unprocessable_entity }
end
end
end
end
Also here is my Rspec users_controller_spec.rb. I made two tests about "POST update". One is for being updated successfully. Another is for not being updated. (About the latter, I put the stub User.stub(:update_attribute).and_return(false) which I expect that "update_attribute" returns "false" so that process proceeds to "else".)
require 'spec_helper'
describe UsersController do
let(:valid_attributes) { {
"email" => "hoge#hogehoge.com",
"password" => "12345678"
} }
def valid_session
{}
end
describe "PUT update" do
it "user update succeeds" do
user = User.create! valid_attributes
put :update, {:id => user.to_param}, valid_session
assigns(:user).should eq(user)
end
it "user update does not succeed" do
user = User.create! valid_attributes
User.stub(:update_attribute).and_return(false)
put :update, {:id => user.to_param}, valid_session
assigns(:user).should eq(user)
response.should render_template("edit")
end
end
end
I have no idea to solve this, because I cannot understand where user_url did come. So I would like to have your help.
When you use redirect_to #user, rails sends that request to UsersController#show, but it does so by calling user_url(#user). If I had to guess, you probably don't have the line that defines user_url:
resources :users
in your routes.rb file. This would automatically create the named route user_url that your controller is referencing with redirect_to #user
Alternatively, you could define the route yourself in your routes.rb file like so:
get "/users/show" => "users#show", as: :user
But that's not really the 'Rails-y' way to do it. At any time, you can run the command rake routes in the terminal to see all the named routes you have defined in your routes.rb file. If user isn't there, then you need to define it like I mentioned above.
More info on named routes here: http://guides.rubyonrails.org/routing.html#singular-resources
If you are using devise then check if the following method returns anything.
def after_sign_in_path_for(resource)
in application_controller.rb
If the method returns nothing you will receive the error:
undefined method `user_url' for #
I also ended up removing
stored_location_for(resource)
in after_sign_in_path_for(resource) because it was causing an endless loop. Refer to this answer for details.
rails:3 Devise signup Filter chain halted as :require_no_authentication rendered or redirected

NoMethodError: undefined method `model_name' for Fixnum:Class

I run an RSpec testcase that fills a form and submits it. I get the following error:
1) Sign Up Advertiser after adding valid information should create a user
Failure/Error: expect { click_button submit }.to change(User, :user_key)
NoMethodError:
undefined method `model_name' for Fixnum:Class
# /mnt/hgfs/Projekte/adserve.example.de/app/controllers/advertisers_controller.rb:31:in `tryToCreateUser'
# /mnt/hgfs/Projekte/adserve.example.de/app/controllers/advertisers_controller.rb:14:in `create'
# ./sign_up_advertiser_spec.rb:32:in `block (4 levels) in <top (required)>'
# ./sign_up_advertiser_spec.rb:32:in `block (3 levels) in <top (required)>'
This is the code for the controller:
class AdvertisersController < ApplicationController
...
def home
#menuindex = 0
end
def create
#user = Advertiser.new (params[:advertiser])
tryToCreateUser
end
def tryToCreateUser
if #user.save
#user = Advertiser.retrieve(#user.id)
redirect_to home, :notice => "You successfully signed up " + #user.full_name
else
render :action => "/users/new", :layout => 'application'
end
end
end
And this is what the routes.rb looks like
match "signup_advertiser" => "advertisers#new", :as => "signup_advertiser"
match "signup_publisher" => "publishers#new", :as => "signup_publisher"
get "advertisers_home" => "advertisers#home"
resources :advertisers
So I guess the mistake is in the redirect_to part. But I can't figure it out. I fiddled around with rendering a custom action in 'home' and some other stuff. I think it's something pretty basic so help would be very appreciated. Thanks.
Yes, the problem is there. You should use home as a symbol on the redirect_to method:
def tryToCreateUser
if #user.save
#user = Advertiser.retrieve(#user.id)
redirect_to :home, :notice => "You successfully signed up " + #user.full_name
else
render :action => "/users/new", :layout => 'application'
end
end
What you do now is: redirect_to 0 since you are actually calling the controllers method "home".

Rails Tutorial 3, RSpec Failures

I'm running through the Ruby on Rails Tutorial 3, and having a ball doing it, but I've just come across some problems that aren't getting solved. When I run my specs, two tests fail.
Failures:
1) UsersController PUT 'update' failure should render the 'edit' page
Failure/Error: put :update, :id => #user, :user => #attr
undefined local variable or method `object' for #<#<Class:0x00000102c861c8>:0x00000101d25558>
# ./app/views/shared/_error_messages.html.erb:3:in `_app_views_shared__error_messages_html_erb___3390867530789228804_2170854120__2806434579894406668'
# ./app/views/users/edit.html.erb:4:in `block in _app_views_users_edit_html_erb__558009768664311469_2170714160__919273585470661416'
# ./app/views/users/edit.html.erb:3:in `_app_views_users_edit_html_erb__558009768664311469_2170714160__919273585470661416'
# ./app/controllers/users_controller.rb:47:in `update'
# ./spec/controllers/users_controller_spec.rb:158:in `block (4 levels) in <top (required)>'
2) UsersController PUT 'update' failure should have the right title
Failure/Error: put :update, :id => #user, :user => #attr
undefined local variable or method `object' for #<#<Class:0x00000102c861c8>:0x00000101b211f8>
# ./app/views/shared/_error_messages.html.erb:3:in `_app_views_shared__error_messages_html_erb___3390867530789228804_2170854120__2806434579894406668'
# ./app/views/users/edit.html.erb:4:in `block in _app_views_users_edit_html_erb__558009768664311469_2170714160__919273585470661416'
# ./app/views/users/edit.html.erb:3:in `_app_views_users_edit_html_erb__558009768664311469_2170714160__919273585470661416'
# ./app/controllers/users_controller.rb:47:in `update'
# ./spec/controllers/users_controller_spec.rb:163:in `block (4 levels) in <top (required)>'
I've searched through my code as best I can comparing it against the code in the book, and I've come up with nothing. I'm sure it's one stupid little thing that I've missed, and I would greatly appreciate a second pair (or more ;) of eyes.
Here are my tests:
describe "failure" do
before(:each) do
#attr = { :email => "", :name => "", :password => "", :password_confirmation => "" }
end
it "should render the 'edit' page" do
put :update, :id => #user, :user => #attr
response.should render_template('edit')
end
it "should have the right title" do
put :update, :id => #user, :user => #attr
response.should have_selector("title", :content => "Edit User")
end
end
And here is the update methods from the users_controller:
def update
#user = User.find(params[:id])
if #user.update_attributes(params[:user])
flash[:success] = "Profile updated"
redirect_to #user
else
#title = "Edit User"
render 'edit'
end
end
Any thoughts on where I should look are greatly appreciated.
The source of the problem is not in spec files even though the problem manifests itself in those spec files. The instructor, Michael Hartl, changes the following statement:
<%= render 'shared/error_messages' %
to
<%= render 'shared/error_messages', :object => f.object %>
statement. In other words, he adds “, :object => f.object” to the first statement. And you must look in all files that have the original statement and change them to the second one. If you miss any of them you will have these errors. Specifically look in the following files (and any other that may have the original statement):
app/views/users/edit.html.erb
app/views/users/fields.html.erb
app/views/users/new.html.erb
app/views/shared/micropost_form.html.erb

Resources