aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/test/dispatch/debug_exceptions_test.rb
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/test/dispatch/debug_exceptions_test.rb')
-rw-r--r--actionpack/test/dispatch/debug_exceptions_test.rb205
1 files changed, 202 insertions, 3 deletions
diff --git a/actionpack/test/dispatch/debug_exceptions_test.rb b/actionpack/test/dispatch/debug_exceptions_test.rb
index d236b14e02..1e5ed60b09 100644
--- a/actionpack/test/dispatch/debug_exceptions_test.rb
+++ b/actionpack/test/dispatch/debug_exceptions_test.rb
@@ -10,6 +10,8 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
@closed = false
end
+ # We're obliged to implement this (even though it doesn't actually
+ # get called here) to properly comply with the Rack SPEC
def each
end
@@ -17,6 +19,10 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
@closed = true
end
+ def method_that_raises
+ raise StandardError.new 'error in framework'
+ end
+
def call(env)
env['action_dispatch.show_detailed_exceptions'] = @detailed
req = ActionDispatch::Request.new(env)
@@ -29,24 +35,53 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
raise RuntimeError
when "/method_not_allowed"
raise ActionController::MethodNotAllowed
+ when "/unknown_http_method"
+ raise ActionController::UnknownHttpMethod
when "/not_implemented"
raise ActionController::NotImplemented
when "/unprocessable_entity"
raise ActionController::InvalidAuthenticityToken
when "/not_found_original_exception"
raise ActionView::Template::Error.new('template', AbstractController::ActionNotFound.new)
+ when "/missing_template"
+ raise ActionView::MissingTemplate.new(%w(foo), 'foo/index', %w(foo), false, 'mailer')
when "/bad_request"
raise ActionController::BadRequest
when "/missing_keys"
raise ActionController::UrlGenerationError, "No route matches"
+ when "/parameter_missing"
+ raise ActionController::ParameterMissing, :missing_param_key
+ when "/original_syntax_error"
+ eval 'broke_syntax =' # `eval` need for raise native SyntaxError at runtime
+ when "/syntax_error_into_view"
+ begin
+ eval 'broke_syntax ='
+ rescue Exception => e
+ template = ActionView::Template.new(File.read(__FILE__),
+ __FILE__,
+ ActionView::Template::Handlers::Raw.new,
+ {})
+ raise ActionView::Template::Error.new(template, e)
+ end
+ when "/framework_raises"
+ method_that_raises
else
raise "puke!"
end
end
end
- ProductionApp = ActionDispatch::DebugExceptions.new(Boomer.new(false))
- DevelopmentApp = ActionDispatch::DebugExceptions.new(Boomer.new(true))
+ def setup
+ app = ActiveSupport::OrderedOptions.new
+ app.config = ActiveSupport::OrderedOptions.new
+ app.config.assets = ActiveSupport::OrderedOptions.new
+ app.config.assets.prefix = '/sprockets'
+ Rails.stubs(:application).returns(app)
+ end
+
+ RoutesApp = Struct.new(:routes).new(SharedTestRoutes)
+ ProductionApp = ActionDispatch::DebugExceptions.new(Boomer.new(false), RoutesApp)
+ DevelopmentApp = ActionDispatch::DebugExceptions.new(Boomer.new(true), RoutesApp)
test 'skip diagnosis if not showing detailed exceptions' do
@app = ProductionApp
@@ -78,6 +113,24 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert boomer.closed, "Expected to close the response body"
end
+ test 'displays routes in a table when a RoutingError occurs' do
+ @app = DevelopmentApp
+ get "/pass", {}, {'action_dispatch.show_exceptions' => true}
+ routing_table = body[/route_table.*<.table>/m]
+ assert_match '/:controller(/:action)(.:format)', routing_table
+ assert_match ':controller#:action', routing_table
+ assert_no_match '&lt;|&gt;', routing_table, "there should not be escaped html in the output"
+ end
+
+ test 'displays request and response info when a RoutingError occurs' do
+ @app = DevelopmentApp
+
+ get "/pass", {}, {'action_dispatch.show_exceptions' => true}
+
+ assert_select 'h2', /Request/
+ assert_select 'h2', /Response/
+ end
+
test "rescue with diagnostics message" do
@app = DevelopmentApp
@@ -93,9 +146,59 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
assert_response 405
assert_match(/ActionController::MethodNotAllowed/, body)
+ get "/unknown_http_method", {}, {'action_dispatch.show_exceptions' => true}
+ assert_response 405
+ assert_match(/ActionController::UnknownHttpMethod/, body)
+
get "/bad_request", {}, {'action_dispatch.show_exceptions' => true}
assert_response 400
assert_match(/ActionController::BadRequest/, body)
+
+ get "/parameter_missing", {}, {'action_dispatch.show_exceptions' => true}
+ assert_response 400
+ assert_match(/ActionController::ParameterMissing/, body)
+ end
+
+ test "rescue with text error for xhr request" do
+ @app = DevelopmentApp
+ xhr_request_env = {'action_dispatch.show_exceptions' => true, 'HTTP_X_REQUESTED_WITH' => 'XMLHttpRequest'}
+
+ get "/", {}, xhr_request_env
+ assert_response 500
+ assert_no_match(/<header>/, body)
+ assert_no_match(/<body>/, body)
+ assert_equal "text/plain", response.content_type
+ assert_match(/RuntimeError\npuke/, body)
+
+ get "/not_found", {}, xhr_request_env
+ assert_response 404
+ assert_no_match(/<body>/, body)
+ assert_equal "text/plain", response.content_type
+ assert_match(/#{AbstractController::ActionNotFound.name}/, body)
+
+ get "/method_not_allowed", {}, xhr_request_env
+ assert_response 405
+ assert_no_match(/<body>/, body)
+ assert_equal "text/plain", response.content_type
+ assert_match(/ActionController::MethodNotAllowed/, body)
+
+ get "/unknown_http_method", {}, xhr_request_env
+ assert_response 405
+ assert_no_match(/<body>/, body)
+ assert_equal "text/plain", response.content_type
+ assert_match(/ActionController::UnknownHttpMethod/, body)
+
+ get "/bad_request", {}, xhr_request_env
+ assert_response 400
+ assert_no_match(/<body>/, body)
+ assert_equal "text/plain", response.content_type
+ assert_match(/ActionController::BadRequest/, body)
+
+ get "/parameter_missing", {}, xhr_request_env
+ assert_response 400
+ assert_no_match(/<body>/, body)
+ assert_equal "text/plain", response.content_type
+ assert_match(/ActionController::ParameterMissing/, body)
end
test "does not show filtered parameters" do
@@ -135,7 +238,30 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
}
})
assert_response 500
- assert_match(/RuntimeError\n in FeaturedTileController/, body)
+ assert_match(/RuntimeError\n\s+in FeaturedTileController/, body)
+ end
+
+ test "show formatted params" do
+ @app = DevelopmentApp
+
+ params = {
+ 'id' => 'unknown',
+ 'someparam' => {
+ 'foo' => 'bar',
+ 'abc' => 'goo'
+ }
+ }
+
+ get("/runtime_error", {}, {
+ 'action_dispatch.show_exceptions' => true,
+ 'action_dispatch.request.parameters' => {
+ 'action' => 'show',
+ 'controller' => 'featured_tile'
+ }.merge(params)
+ })
+ assert_response 500
+
+ assert_includes(body, CGI.escapeHTML(PP.pp(params, "", 200)))
end
test "sets the HTTP charset parameter" do
@@ -171,4 +297,77 @@ class DebugExceptionsTest < ActionDispatch::IntegrationTest
get "/", {}, env
assert_operator((output.rewind && output.read).lines.count, :>, 10)
end
+
+ test 'display backtrace when error type is SyntaxError' do
+ @app = DevelopmentApp
+
+ get '/original_syntax_error', {}, {'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new}
+
+ assert_response 500
+ assert_select '#Application-Trace' do
+ assert_select 'pre code', /\(eval\):1: syntax error, unexpected/
+ end
+ end
+
+ test 'display backtrace on template missing errors' do
+ @app = DevelopmentApp
+
+ get "/missing_template", nil, {}
+
+ assert_select "header h1", /Template is missing/
+
+ assert_select "#container h2", /^Missing template/
+
+ assert_select '#Application-Trace'
+ assert_select '#Framework-Trace'
+ assert_select '#Full-Trace'
+
+ assert_select 'h2', /Request/
+ end
+
+ test 'display backtrace when error type is SyntaxError wrapped by ActionView::Template::Error' do
+ @app = DevelopmentApp
+
+ get '/syntax_error_into_view', {}, {'action_dispatch.backtrace_cleaner' => ActiveSupport::BacktraceCleaner.new}
+
+ assert_response 500
+ assert_select '#Application-Trace' do
+ assert_select 'pre code', /\(eval\):1: syntax error, unexpected/
+ end
+ end
+
+ test 'debug exceptions app shows user code that caused the error in source view' do
+ @app = DevelopmentApp
+ Rails.stubs(:root).returns(Pathname.new('.'))
+ cleaner = ActiveSupport::BacktraceCleaner.new.tap do |bc|
+ bc.add_silencer { |line| line =~ /method_that_raises/ }
+ bc.add_silencer { |line| line !~ %r{test/dispatch/debug_exceptions_test.rb} }
+ end
+
+ get '/framework_raises', {}, {'action_dispatch.backtrace_cleaner' => cleaner}
+
+ # Assert correct error
+ assert_response 500
+ assert_select 'h2', /error in framework/
+
+ # assert source view line is the call to method_that_raises
+ assert_select 'div.source:not(.hidden)' do
+ assert_select 'pre .line.active', /method_that_raises/
+ end
+
+ # assert first source view (hidden) that throws the error
+ assert_select 'div.source:first' do
+ assert_select 'pre .line.active', /raise StandardError\.new/
+ end
+
+ # assert application trace refers to line that calls method_that_raises is first
+ assert_select '#Application-Trace' do
+ assert_select 'pre code a:first', %r{test/dispatch/debug_exceptions_test\.rb:\d+:in `call}
+ end
+
+ # assert framework trace that that threw the error is first
+ assert_select '#Framework-Trace' do
+ assert_select 'pre code a:first', /method_that_raises/
+ end
+ end
end