Skip to content

Commit

Permalink
Merge pull request #157 from sh19910711/patch/0020/show-error-message
Browse files Browse the repository at this point in the history
Show an error message when an error response does not have JSON
  • Loading branch information
gsamokovarov committed Aug 14, 2015
2 parents 3bf8cc5 + 0f47ed9 commit ba5a850
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 57 deletions.
12 changes: 11 additions & 1 deletion extensions/chrome/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,21 @@ function initPanelMessage() {
function initReqRes() {
chrome.runtime.onMessage.addListener(handleMessage);

function extractProps(xhr) {
var props = {};
for (var key in xhr) {
if (typeof xhr[key] === 'string' || typeof xhr[key] === 'number') {
props[key] = xhr[key];
}
}
return props;
}

function handleMessage(req, sender, sendResponse) {
if (req.type === 'request') {
var url = tabInfo[req.tabId].remoteHost + '/' + req.url;
REPLConsole.request(req.method, url, req.params, function(xhr) {
sendResponse({ status: xhr.status, responseText: xhr.responseText });
sendResponse(extractProps(xhr));
});
}
return true;
Expand Down
1 change: 1 addition & 0 deletions lib/web_console.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
require 'web_console/whitelist'
require 'web_console/request'
require 'web_console/response'
require 'web_console/view'

module WebConsole
mattr_accessor :logger
Expand Down
15 changes: 15 additions & 0 deletions lib/web_console/locales/en.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
en:
errors:
unavailable_session: |
Session %{id} is is no longer available in memory.
If you happen to run on a multi-process server (like Unicorn or Puma) the process
this request hit doesn't store %{id} in memory. Consider turning the number of
processes/workers to one (1) or using a different server in development.
unacceptable_request: |
A supported version is expected in the Accept header.
connection_refused: |
Oops! Failed to connect to the Web Console middleware.
Please make sure a rails development server is running.
14 changes: 2 additions & 12 deletions lib/web_console/middleware.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,6 @@ module WebConsole
class Middleware
TEMPLATES_PATH = File.expand_path('../templates', __FILE__)

UNAVAILABLE_SESSION_MESSAGE = <<-END.strip_heredoc
Session %{id} is is no longer available in memory.
If you happen to run on a multi-process server (like Unicorn or Puma) the process
this request hit doesn't store %{id} in memory. Consider turning the number of
processes/workers to one (1) or using a different server in development.
END

UNACCEPTABLE_REQUEST_MESSAGE = "A supported version is expected in the Accept header."

cattr_accessor :mount_point
@@mount_point = '/__web_console'

Expand Down Expand Up @@ -115,13 +105,13 @@ def change_stack_trace(id, request)

def respond_with_unavailable_session(id)
json_response(status: 404) do
{ output: format(UNAVAILABLE_SESSION_MESSAGE, id: id)}
{ output: format(I18n.t('errors.unavailable_session'), id: id)}
end
end

def respond_with_unacceptable_request
json_response(status: 406) do
{ error: UNACCEPTABLE_REQUEST_MESSAGE }
{ output: I18n.t('errors.unacceptable_request') }
end
end
end
Expand Down
4 changes: 4 additions & 0 deletions lib/web_console/railtie.rb
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,9 @@ class Railtie < ::Rails::Railtie
Middleware.whiny_requests = config.web_console.whiny_requests
end
end

initializer 'i18n.load_path' do
config.i18n.load_path.concat(Dir[File.expand_path('../locales/*.yml', __FILE__)])
end
end
end
31 changes: 2 additions & 29 deletions lib/web_console/template.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,6 @@ module WebConsole
# It introduces template helpers to ease the inclusion of scripts only on
# Rails error pages.
class Template
class Context < ActionView::Base
# Execute a block only on error pages.
#
# The error pages are special, because they are the only pages that
# currently require multiple bindings. We get those from exceptions.
def only_on_error_page(*args)
yield if @env['web_console.exception'].present?
end

# Render JavaScript inside a script tag and a closure.
#
# This one lets write JavaScript that will automatically get wrapped in a
# script tag and enclosed in a closure, so you don't have to worry for
# leaking globals, unless you explicitly want to.
def render_javascript(template)
render(template: template, layout: 'layouts/javascript')
end

# Render inlined string to be used inside of JavaScript code.
#
# The inlined string is returned as an actual JavaScript string. You
# don't need to wrap the result yourself.
def render_inlined_string(template)
render(template: template, layout: 'layouts/inlined_string')
end
end

# Lets you customize the default templates folder location.
cattr_accessor :template_paths
@@template_paths = [ File.expand_path('../templates', __FILE__) ]
Expand All @@ -43,8 +16,8 @@ def initialize(env, session)

# Render a template (inferred from +template_paths+) as a plain string.
def render(template)
context = Context.new(template_paths, instance_values)
context.render(template: template, layout: false)
view = View.new(template_paths, instance_values)
view.render(template: template, layout: false)
end
end
end
24 changes: 22 additions & 2 deletions lib/web_console/templates/console.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,33 @@ REPLConsole.prototype.commandHandle = function(line, callback) {
return status >= 200 && status < 300 || status === 304;
}

function parseJSON(text) {
try {
return JSON.parse(text);
} catch (e) {
return null;
}
}

function getErrorText(xhr) {
if (!xhr.status) {
return "<%= t 'errors.connection_refused' %>";
} else {
return xhr.status + ' ' + xhr.statusText;
}
}

putRequest(self.getUrl(), params, function(xhr) {
var response = JSON.parse(xhr.responseText);
var response = parseJSON(xhr.responseText);
var result = isSuccess(xhr.status);
if (result) {
self.writeOutput(response.output);
} else {
self.writeError(response.output);
if (response && response.output) {
self.writeError(response.output);
} else {
self.writeError(getErrorText(xhr));
}
}
callback(result, response);
});
Expand Down
16 changes: 3 additions & 13 deletions lib/web_console/testing/fake_middleware.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
require 'action_view'
require 'action_dispatch'
require 'active_support/core_ext/string/access'
require 'json'
require 'web_console/whitelist'
require 'web_console/request'
require 'web_console/view'

module WebConsole
module Testing
Expand All @@ -20,7 +22,7 @@ def call(env)
end

def view
@view ||= create_view
@view ||= View.new(@view_path)
end

private
Expand All @@ -33,18 +35,6 @@ def req_path(env)
def render(template)
view.render(template: template, layout: nil)
end

def create_view
lookup_context = ActionView::LookupContext.new(@view_path)
lookup_context.cache = false
FakeView.new(lookup_context)
end

class FakeView < ActionView::Base
def render_inlined_string(template)
render(template: template, layout: "layouts/inlined_string")
end
end
end
end
end
33 changes: 33 additions & 0 deletions lib/web_console/view.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module WebConsole
class View < ActionView::Base
# Execute a block only on error pages.
#
# The error pages are special, because they are the only pages that
# currently require multiple bindings. We get those from exceptions.
def only_on_error_page(*args)
yield if @env['web_console.exception'].present?
end

# Render JavaScript inside a script tag and a closure.
#
# This one lets write JavaScript that will automatically get wrapped in a
# script tag and enclosed in a closure, so you don't have to worry for
# leaking globals, unless you explicitly want to.
def render_javascript(template)
render(template: template, layout: 'layouts/javascript')
end

# Render inlined string to be used inside of JavaScript code.
#
# The inlined string is returned as an actual JavaScript string. You
# don't need to wrap the result yourself.
def render_inlined_string(template)
render(template: template, layout: 'layouts/inlined_string')
end

# Escaped alias for "ActionView::Helpers::TranslationHelper.t".
def t(key, options = {})
super.gsub("\n", "\\n")
end
end
end
6 changes: 6 additions & 0 deletions test/templates/config.ru
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,9 @@ map "/mock/repl/error" do
body = [ { output: 'fake-error-message' }.to_json ]
run lambda { |env| [ 400, headers, body ] }
end

map "/mock/repl_sessions/error.txt" do
headers = { 'Content-Type' => 'plain/text' }
body = [ 'error message' ]
run lambda { |env| [ 400, headers, body ] }
end
15 changes: 15 additions & 0 deletions test/templates/spec/repl_console_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,21 @@ describe("REPLConsole", function() {
assert.ok(hasClass(this.message, 'error-message'));
});
});

context("remotePath: /mock/repl_sessions/error.txt", function() {
beforeEach(function(done) {
var self = this;
var options = { remotePath: '/mock/repl_sessions/error.txt' };
self.console = REPLConsole.installInto('console', options);
self.console.commandHandle('fake-input', function(result, response) {
self.message = self.elm.getElementsByClassName('console-message')[0];
done();
});
});
it("should output HTTP status code", function() {
assert.match(this.message.innerHTML, /400 Bad Request/);
});
});
});

describe(".installInto()", function() {
Expand Down

0 comments on commit ba5a850

Please sign in to comment.