require 'spec_helper' describe RailsExceptionHandler::Handler do before(:each) do @handler = RailsExceptionHandler::Handler.new(create_env, create_exception) end describe ".handle_exception" do it "should parse error" do @handler.handle_exception @handler.instance_variable_get(:@parsed_error).should_not == nil end it "should store error" do @handler.should_receive(:store_error) @handler.handle_exception end it "should return a rack tripple" do response = @handler.handle_exception response.length.should == 3 response[0].should == 500 # response code response[1].class.should == Hash # headers response[2].class.should == ActionDispatch::Response # body end it "should set the response code to 404 on routing errors" do exception = create_exception exception.stub!(:class => ActionController::RoutingError) handler = RailsExceptionHandler::Handler.new(create_env, exception) response = handler.handle_exception response.length.should == 3 response[0].should == 404 end end describe ".store_error" do it "should store an error message in the database when storage_strategies includes :active_record" do RailsExceptionHandler.configure { |config| config.storage_strategies = [:active_record] } @handler.handle_exception ErrorMessage.count.should == 1 msg = ErrorMessage.first msg.app_name.should == 'ExceptionHandlerTestApp' msg.class_name.should == 'NoMethodError' msg.message.should == "undefined method `foo' for nil:NilClass" msg.trace.should match /active_support\/whiny_nil/ msg.params.should match /\"foo\"=>\"bar\"/ msg.user_agent.should == 'Mozilla/4.0 (compatible; MSIE 8.0)' msg.target_url.should == 'http://example.org/home?foo=bar' msg.referer_url.should == 'http://google.com/' msg.created_at.should be > 5.seconds.ago msg.created_at.should be < Time.now end it "should not store an error message in the database when storage_strategies does not include :active_record" do RailsExceptionHandler.configure { |config| config.storage_strategies = [] } ErrorMessage.count.should == 0 end it "it should log an error to the rails log when storage_strategies includes :rails_log" do RailsExceptionHandler.configure { |config| config.storage_strategies = [:rails_log] } read_test_log.should == '' @handler.handle_exception read_test_log.should match /NoMethodError \(undefined method `foo' for nil:NilClass\)/ read_test_log.should match /lib\/active_support\/whiny_nil\.rb:48/ read_test_log.should match /PARAMS:\s+\{\"foo\"=>\"bar\"\}/ read_test_log.should match /USER_AGENT:\s+Mozilla\/4.0 \(compatible; MSIE 8\.0\)/ read_test_log.should match /TARGET:\s+http:\/\/example\.org\/home\?foo=bar/ read_test_log.should match /REFERER:\s+http:\/\/google\.com\// end it "should not log an error to the rails log when storage_strategies does not include :rails_log" do RailsExceptionHandler.configure { |config| config.storage_strategies = [] } read_test_log.should == '' @handler.handle_exception read_test_log.should == '' end it "should send the error_message as an HTTP POST request when :remote_url is included" do Time.stub!(:now => Time.now) # Otherwise the timestamps will be different, and comparison fail @handler.handle_exception parser = @handler.instance_variable_get(:@parsed_error) RailsExceptionHandler.configure { |config| config.storage_strategies = [:remote_url => {:target => 'http://example.com/error_messages'}] } uri = URI.parse('http://example.com/error_messages') params = {} parser.relevant_info.each do |key,value| params["error_message[#{key}]"] = value end Net::HTTP.should_receive(:post_form).with(uri, params) @handler.handle_exception end it "should not send the error_message as an HTTP POST request when :remote_url is not included" do RailsExceptionHandler.configure { |config| config.storage_strategies = [] } Net::HTTP.should_not_receive(:post_form) @handler.handle_exception end it "should be able to use multiple storage strategies" do RailsExceptionHandler.configure { |config| config.storage_strategies = [:active_record, :rails_log] } read_test_log.should == '' @handler.handle_exception read_test_log.should match /NoMethodError \(undefined method `foo' for nil:NilClass\)/ ErrorMessage.count.should == 1 end end describe '.response' do it "should call index action on ErrorResponseController" do ErrorResponseController.should_receive(:action).with(:index).and_return(mock(Object, :call => [500, {}, {}])) @handler.handle_exception end it "should set response_code to '404' on routing errors" do exception = create_exception env = create_env exception.stub!(:class => ActiveRecord::RecordNotFound) handler = RailsExceptionHandler::Handler.new(env, exception) response = handler.handle_exception response[0].should == 404 end it "should set response_code to '500' on all other errors" do env = create_env handler = RailsExceptionHandler::Handler.new(env, create_exception) response = handler.handle_exception response[0].should == 500 end it "should save the layout in env" do env = create_env handler = RailsExceptionHandler::Handler.new(env, create_exception) handler.instance_variable_set("@controller",mock(Object, :_default_layout => 'home')) handler.handle_exception env['exception_handler.layout'].should == 'home' end it "should use the fallback layout when no layout is defined" do env = create_env handler = RailsExceptionHandler::Handler.new(env, create_exception) handler.handle_exception env['exception_handler.layout'].should == 'fallback' end end describe '.response_layout' do it "should not set a layout for XHR requests" do handler = RailsExceptionHandler::Handler.new(create_env, create_exception) handler.handle_exception request = handler.instance_variable_get(:@request) request.stub!(:xhr? => true) handler.instance_variable_set(:@request, request) handler.send(:response_layout).should == false end it "should use the controllers default layout if it exists" do env = create_env controller = ApplicationController.new controller.stub!(:_default_layout => 'home') env['action_controller.instance'] = controller handler = RailsExceptionHandler::Handler.new(env, create_exception) handler.handle_exception handler.send(:response_layout).should == 'home' end it "should use the fallback layout if the controller does not have a default layout" do handler = RailsExceptionHandler::Handler.new(create_env, create_exception) handler.handle_exception handler.send(:response_layout).should == 'fallback' end end describe '.response_text' do it "should return the response mapped to the exception class if it exists" do RailsExceptionHandler.configure { |config| config.responses[:not_found] = 'Page not found' config.response_mapping = {'ActiveRecord::RecordNotFound' => :not_found} } env = create_env exception = create_exception exception.stub!(:class => ActiveRecord::RecordNotFound) handler = RailsExceptionHandler::Handler.new(env, exception) handler.handle_exception handler.send(:response_text).should == 'Page not found' end it "should return the default response if a mapping does not exist" do RailsExceptionHandler.configure { |config| config.responses[:default] = 'Default response' config.response_mapping = {} } env = create_env exception = create_exception exception.stub!(:class => ActiveRecord::RecordNotFound) handler = RailsExceptionHandler::Handler.new(env, exception) handler.handle_exception handler.send(:response_text).should == 'Default response' end end end