I'm working my way through Michael Hartl's Rails Tutorial. I hit a snag in Chapter 3 Section 3 on Testing. After generating two controllers - home and help, I ran the following in the terminal:
bundle exec rake test
The test should have passed but I received the following error for both the home and help controllers:
1) Error:
StaticPagesControllerTest#test_should_get_home:
SyntaxError: /home/ubuntu/workspace/sample_app/app/controllers /application_controller.rb:7: syntax error, unexpected tSTRING_BEG, expecting keyword_end
render :text "hello, world!"
^
app/controllers/static_pages_controller.rb:1:in `<top (required)>'
I have reviewed the code and haven't seen anywhere the end keyword should be required.
My static_pages_controller_test.rb file is setup as follows:
require 'test_helper'
class StaticPagesControllerTest < ActionController::TestCase
test "should get home" do
get :home
assert_response :success
end
test "should get help" do
get :help
assert_response :success
end
end
static_pages_controller.rb has the following code:
class StaticPagesController < ApplicationController
def home
end
def help
end
end
application_controller.rb has this code:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
def hello
render :text "hello, world!"
end
end
routes.rb has this code:
Rails.application.routes.draw do
get 'static_pages/home'
get 'static_pages/help'
root 'application#hello'
end
Any thoughts on what the problem might be? I have search this site with no luck. Thanks in advance for your help.
I am not sure but isn't it should be like this
respond_to do |format|
format.html
format.js { render :text => "hello, world!" }
end
Related
I'm currently attempting my first unit test and I'm receiving the following errors
Failures:
1) StaticPagesController GET #index responds successfully with an HTTP 200 status code
Failure/Error: get :index
NoMethodError:
undefined method `authenticate!' for nil:NilClass
# /Users/danielmayle/.rvm/gems/ruby-2.2.1/gems/devise-3.5.2/lib/devise/controllers/helpers.rb:112:in `authenticate_user!'
# ./spec/static_pages_controller_spec.rb:6:in `block (3 levels) in <top (required)>'
2) StaticPagesController GET #index renders the index template
Failure/Error: get :index
NoMethodError:
undefined method `authenticate!' for nil:NilClass
# /Users/danielmayle/.rvm/gems/ruby-2.2.1/gems/devise-3.5.2/lib/devise/controllers/helpers.rb:112:in `authenticate_user!'
# ./spec/static_pages_controller_spec.rb:6:in `block (3 levels) in <top (required)>'
Here is my unit test code:
require 'rails_helper'
describe StaticPagesController, :type => :controller do
context "GET #index" do
before do
get :index
end
it "responds successfully with an HTTP 200 status code" do
expect(response).to be_success
expect(response).to have_http_status(200)
end
it "renders the index template" do
expect(response).to render_template("index")
end
end
end
And here is my static_controller.rb code:
class StaticPagesController < ApplicationController
def index
end
def landing_page
#featured_product = Product.first
end
def thank_you
#name = params[:name]
#email = params[:email]
#message = params[:message]
UserMailer.contact_form(#email, #name, #message).deliver_now
end
end
Why do are these errors coming up and how do I fix the problem? I've only been coding for a few months so any assistance would be much appreciated. Thanks :)
Update
Here is my application controller
class ApplicationController < ActionController::Base
before_action :authenticate_user!
before_action :configure_permitted_parameters, if: :devise_controller?
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
rescue_from CanCan::AccessDenied do |exception|
redirect_to main_app.root_url, :alert => exception.message
end
protected
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_up) << :username
end
end
Here is my user_mailer code as well
class UserMailer < ActionMailer::Base
default from: "dmayle012#gmail.com"
def contact_form(email, name, message)
#message = message
mail(:from => email,
:to => 'dmayle012#gmail.com',
:subject => "New ActionMail Message from #{name}")
end
end
Your problem is this line:
before_action :authenticate_user!
This makes devise to check authorisation for current_user, which is nil in your test. There are two ways to fix it depending on what your requirements are.
Firstly, if you want any internet user to be able to view your static pages without login, add:
skip_before_action :authenticate_user!
in your StaticPagesController. This will tell devise that you don't require current_user to be allowed to view the page (not really - it doesn't tell devise anything, it just not asking it to authorise user).
Second option - you need user to be logged in to view those pages. In this case you need to create fake session before you start your test using some helper methods provided by devise. This is very easy and well documented process, you can find the steps here: https://github.com/plataformatec/devise/wiki/How-To:-Test-controllers-with-Rails-3-and-4-(and-RSpec)#controller-specs. Not adding those steps in the answer as I believe you will go with first case (since every page requires some pages available without the session, at least for the login page).
Devise has some helper methods specifically for this. Here is how to setup your controller spec to get past your undefined method authenticate_user! for nil error
First you need to include them in your rails_helper.rb like this
# spec/rails_helper.rb
RSpec.configure do |config|
config.include Devise::TestHelpers, type: :controller
end
And then you can use the helper like this in your static pages controller
# spec/controllers/static_pages_controller_spec.rb
describe StaticPagesController, :type => :controller do
context "GET #index" do
before :each do
user = FactoryGirl.create(:user, approved: true)
sign_in :user, user
get :index
end
...
end
end
I am learning Rails and very new to testing but so far I've managed to build something with minimal errors. However, the issue I am running into is that my tests are complaining for methods that cannot be found and no route matching.
To my understanding tests should be run frequently based Hartl's - Railstutorial 3.3. Many StackO threads and online articles seem to pertain to utilizing test suites I don't use like RSpec, etc...so the test configurations are confusing. My testing suite is set up similiar to Hartl's - Railstutorial 3.3 and below are the gems loaded for testing.
gem 'better_errors', '~> 2.1.1'
gem 'binding_of_caller'
gem 'minitest-reporters', '1.0.5'
gem 'mini_backtrace', '0.1.3'
gem 'guard-minitest', '2.3.1'
gem 'ruby-prof'
NoMethodError: undefined method
Error: (_I have two error similar errors to below_)
ServicesControllerTest#test_should_get_index:
NoMethodError: undefined method 'services' for nil:NilClass
app/controllers/services_controller.rb:6:in 'index'
test/controllers/services_controller_test.rb:9:in 'block in <class:ServicesControllerTest>"
Services Controller
def index
#services = current_tech.services
end
services_controller_test.rb
require 'test_helper'
class ServicesControllerTest < ActionController::TestCase
setup do
#service = services(:one)
end
test "should get index" do
get :index
assert_response :success
assert_not_nil assigns(:services)
end
end
I believe the reason I am receiving this error is because of Devise.
If I were to setup the following index action below, the test will pass.
def index
#services = Tech.first.services
end
How do I correct this so that this test passes?
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"tech"}
Error:
CarsControllerTest#test_should_get_show:
ActionController::UrlGenerationError: No route matches {:action=>"show", :controller=>"cars"}
test/controllers/cars_controller_test.rb:5:in `block in <class:CarsControllerTest>
Rake routes pertaining to cars
tech_cars POST - /techs/:tech_id/cars(.:format) - cars#create
car GET - /cars/:id(.:format) - cars#show
Routes
Rails.application.routes.draw do
devise_for :customers, controllers: { sessions: 'customers/sessions' }
devise_for :techs, controllers: { sessions: 'techs/sessions' }
resources :techs, :only => [:index, :show], shallow: true do
resources :cars, only: [:show, :create]
end
resources :services, :garages
root "home#index"
end
cars_controller.rb
class CarsController < ApplicationController
before_action :set_car
def show
#garage = Garage.find(params[:id])
#tech = #tech.service.car.id
end
def create
#garage = Garage.create(tech_first_name: #car.service.tech.first_name,
customer_id: current_customer.id,
customer_street_address: current_customer.street_address,
customer_city: current_customer.city,
customer_state: current_customer.state,
customer_zip_code: current_customer.zip_cod)
if #garage.save
redirect_to techs_path, notice: "Working"
else
redirect_to techs_path, notice: "Uh oh, flat tire"
end
end
private
def set_car
#car = Car.find(params[:id])
end
def car_params
params.permit(:service_name, :garage_photo)
end
end
cars_controller_test.rb
require 'test_helper'
class CarControllerTest < ActionController::TestCase
test "should get show" do
get :show
assert_response :success
end
end
cars.html.erb (only links on page)
<%= button_to 'View Garage', tech_cars_path(tech_id: #car.service.tech.id, id: #car) %>
<%= link_to 'Back to tech', tech_path(#car.service.tech.id) %>
As you may gather, I am building a Garage not a Car object within the Cars controller. Would this be a problem for tests? My application functions fine as is. On a side note, I am also having difficulty trying to associate car_params strong params for instance variables but that's another StackO post.
*test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require "minitest/reporters"
Minitest::Reporters.use!
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
# Add more helper methods to be used by all tests here...
end
class ActionController::TestCase
include Devise::TestHelpers
end
Is there something I am missing or haven't configured correctly?
Please know my application appears to be working fine, it's just I would like to suppress these tests errors.
Please advise on how to get these test errors to pass.
Thanks
First issue: Your feeling is correct. Devise comes with Devise::TestHelpers which you've mixed into ActionController::TestCase in your test helper file. One of the methods it provides is sign_in which lets you spoof a logged in user as part of your test. Assuming you've got a model called Tech and you're following standard Rails conventions, you'll need to add something like:
sign_in techs(:some_tech)
to either your setup block or directly into your test body before the call to get :index. That will ensure that current_tech returns something non-nil and remove the immediate NoMethodError.
Second issue: Your :show action expects to receive the ID of a known Car as part of the URL. Replace your current invocation of the controller with:
require 'test_helper'
class CarControllerTest < ActionController::TestCase
setup do
#car = cars(:some_car)
end
test "should get show" do
get :show, id: #car.id
assert_response :success
end
end
I'm using rspec-rails (2.8.1) to functional test a rails 3.1 app using mongoid (3.4.7) for persistence. I'm trying test rescue_from for Mongoid::Errors::DocumentNotFound errors in my ApplicationController in the same way that the rspec-rails documentation for anonymous controllers suggests it could be done. But when I run the following test...
require "spec_helper"
class ApplicationController < ActionController::Base
rescue_from Mongoid::Errors::DocumentNotFound, :with => :access_denied
private
def access_denied
redirect_to "/401.html"
end
end
describe ApplicationController do
controller do
def index
raise Mongoid::Errors::DocumentNotFound
end
end
describe "handling AccessDenied exceptions" do
it "redirects to the /401.html page" do
get :index
response.should redirect_to("/401.html")
end
end
end
I get the following unexpected error
1) ApplicationController handling AccessDenied exceptions redirects to the /401.html page
Failure/Error: raise Mongoid::Errors::DocumentNotFound
ArgumentError:
wrong number of arguments (0 for 2)
# ./spec/controllers/application_controller_spec.rb:18:in `exception'
# ./spec/controllers/application_controller_spec.rb:18:in `raise'
# ./spec/controllers/application_controller_spec.rb:18:in `index'
# ./spec/controllers/application_controller_spec.rb:24:in `block (3 levels) in <top (required)>'
Why? How can I raise this mongoid error?
Mongoid's documentation for the exception shows it must be initialized. The corrected, working code is as follows:
require "spec_helper"
class SomeBogusClass; end
class ApplicationController < ActionController::Base
rescue_from Mongoid::Errors::DocumentNotFound, :with => :access_denied
private
def access_denied
redirect_to "/401.html"
end
end
describe ApplicationController do
controller do
def index
raise Mongoid::Errors::DocumentNotFound.new SomeBogusClass, {}
end
end
describe "handling AccessDenied exceptions" do
it "redirects to the /401.html page" do
get :index
response.should redirect_to("/401.html")
end
end
end
I am attempting to create an API with Rails using BDD with RSpec.
Rails version is 3.1.1, Ruby version is 1.9.2, Devise version is 1.5.3, and rspec version is 2.7.0. I am relatively new to Rails and very new to RSpec.
I have defined a simple RSpec as follows to test a FormsController with essentially no logic.
describe FormsController, " handling GET /forms" do
include Devise::TestHelpers
render_views
before do
user = Factory.create(:user) # Handle Devise authentication
user.confirm!
sign_in user
#form = mock_model(Form)
Form.stub!(:all).and_return([ #form ])
end
it "gets successfully" do
get :index, :format => :json
response.should be_success
end
it "finds all forms" do
Form.should_receive(:all).and_return([#form])
get :index, :format => :json
Rails.logger.info "*** response.body="+response.body
end
end
Form controller code is very simple currently.
class FormsController < ApplicationController
before_filter :authenticate_user!
# GET /forms
# GET /forms.json
def index
#forms = Form.find_all_by_owner_id(current_user.id)
respond_to do |format|
format.html # index.html.erb
format.json { render :json => #forms }
end
end
end
When I run the spec, "finds all forms" always fails with
Failure/Error: Form.should_receive(:all).and_return([#form])
(<Form(id: integer, title: string, owner_id: integer, created_at: datetime, updated_at: datetime) (class)>).all(any args)
expected: 1 time
received: 0 times
The output from log/test.log shows:
*** response.body=[]
Why? I feel that the problem stems from Form.stub!(:all).and_return([ #form ]), but I am not sure how to debug.
Thanks in advance.
It would help to post your controller code (that is being tested). The error says that the declaration Form.should_receive(:all).and_return([#form]) has not been satisfied. The declaration says you should have code like this in your controller's action: Form.all.
find_all_by_owner_id is not the same as Form.all. find_all_by_owner_id ends up doing
Form.where(...).all
which doesn't match the expectations you've set. In your particular case I'd tell should_receive that I'm expecting a call to find_all_by_owner_id rather than all.
After much more trial and error, the following solution worked for me.
I migrated from mocking the Form model to using Factory Girl to create the full model
I then updated the test to use to_json to compare the response against the model.
The spec is as follows.
describe FormsController, " handling GET /forms" do
include Devise::TestHelpers
render_views
before do
user = Factory.create(:user) # Handle Devise authentication
user.confirm!
sign_in user
#form1 = Factory.create(:form)
end
it "gets successfully" do
get :index, :format => :json
response.should be_success
end
it "finds all forms" do
get :index, :format => :json
response.body.should == [ #form1 ].to_json
Rails.logger.info "*** response.body="+response.body
end
end
I'm following along with RailsSpace: Building a Social Networking Website with Ruby on Rails by Michael Hartl. Running rails v2.3.2.
I've gotten to the 5th chapter in which testing is introduced. The following is supposed to match the title of the various pages to strings using the get method:
require File.dirname(__FILE__) + '/../test_helper'
require 'site_controller'
# Re-raise errors caught by the controller.
class SiteController; def rescue_action(e) raise e end; end
class SiteControllerTest < Test::Unit::TestCase
def setup
#controller = SiteController.new
#request = ActionController::TestRequest.new
#response = ActionController::TestResponse.new
end
def test_index
get :index
title = assigns(:title)
assert_equal "Welcome to RailsSpace!", title
assert_response :success
assert_template "index"
end
def test_about
get :title
title = assigns(:title)
assert_equal "About RailsSpace", title
assert_response :success
assert_template "about"
end
def test_help
get :help
title = assigns(:title)
assert_equal "RailsSpace Help", title
assert_response :success
assert_template "help"
end
end
On compiling I get:
Loaded suite site_controller_test
Started
EEE
Finished in 0.057 seconds.
1) Error:
test_about(SiteControllerTest):
NoMethodError: undefined method `get' for #<SiteControllerTest:0x4854b30>
site_controller_test.rb:23:in `test_about'
2) Error:
test_help(SiteControllerTest):
NoMethodError: undefined method `get' for #<SiteControllerTest:0x4854b1c>
site_controller_test.rb:31:in `test_help'
3) Error:
test_index(SiteControllerTest):
NoMethodError: undefined method `get' for #<SiteControllerTest:0x485470c>
site_controller_test.rb:15:in `test_index'
3 tests, 0 assertions, 0 failures, 3 errors
Other people have had this issue and the only proposed solution is just to reinstall. I'm not to enthused by this. Since this is an older book there this is probably just breakage between rails versions. What would be the equivalent of this for rails v2.3.2?
Replace all the following code
# Re-raise errors caught by the controller.
class SiteController; def rescue_action(e) raise e end; end
class SiteControllerTest < Test::Unit::TestCase
def setup
#controller = SiteController.new
#request = ActionController::TestRequest.new
#response = ActionController::TestResponse.new
end
with
class SiteControllerTest < ActionController::TestCase
The code you are using refers to Rails 2.0/2.1.
Try changing Test::Unit::TestCase to ActionController::TestCase.
One other thing you might like to know is that Railspace has evolved into Insoshi so the latest code is available there. Might be handy for you when you run into other issues.