diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d455aa932..4737eefe5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,9 @@ Please follow the recommendations outlined at [keepachangelog.com](http://keepac ### [Unreleased] Changes since the last non-beta release. +#### Fixed +- Fix obscure errors by introducing FULL_TEXT_ERRORS [PR 1695](https://github.com/shakacode/react_on_rails/pull/1695) by [Romex91](https://github.com/Romex91). + ### [14.1.1] - 2025-01-15 #### Fixed diff --git a/lib/react_on_rails/prerender_error.rb b/lib/react_on_rails/prerender_error.rb index bb9c617c93..096fae6db6 100644 --- a/lib/react_on_rails/prerender_error.rb +++ b/lib/react_on_rails/prerender_error.rb @@ -1,5 +1,7 @@ # frozen_string_literal: true +require "rainbow" + # rubocop:disable: Layout/IndentHeredoc module ReactOnRails class PrerenderError < ::ReactOnRails::Error @@ -51,11 +53,17 @@ def calc_message(component_name, console_messages, err, js_code, props) message << <<~MSG Encountered error: - #{err} + #{err.inspect} MSG - backtrace = err.backtrace.first(15).join("\n") + backtrace = if Utils.full_text_errors_enabled? + err.backtrace.join("\n") + else + "#{Rails.backtrace_cleaner.clean(err.backtrace).join("\n")}\n" + + Rainbow("The rest of the backtrace is hidden. " \ + "To see the full backtrace, set FULL_TEXT_ERRORS=true.").red + end else backtrace = nil end diff --git a/lib/react_on_rails/utils.rb b/lib/react_on_rails/utils.rb index bd50dd8da5..c2b0b48766 100644 --- a/lib/react_on_rails/utils.rb +++ b/lib/react_on_rails/utils.rb @@ -8,7 +8,9 @@ module ReactOnRails module Utils - TRUNCATION_FILLER = "\n... TRUNCATED ...\n" + TRUNCATION_FILLER = "\n... TRUNCATED #{ + Rainbow('To see the full output, set FULL_TEXT_ERRORS=true.').red + } ...\n".freeze # https://forum.shakacode.com/t/yak-of-the-week-ruby-2-4-pathname-empty-changed-to-look-at-file-size/901 # return object if truthy, else return nil @@ -183,9 +185,14 @@ def self.react_on_rails_pro_version end end + def self.full_text_errors_enabled? + ENV["FULL_TEXT_ERRORS"] == "true" + end + def self.smart_trim(str, max_length = 1000) # From https://stackoverflow.com/a/831583/1009332 str = str.to_s + return str if full_text_errors_enabled? return str unless str.present? && max_length >= 1 return str if str.length <= max_length diff --git a/spec/react_on_rails/prender_error_spec.rb b/spec/react_on_rails/prender_error_spec.rb index f824cf5351..05503830ba 100644 --- a/spec/react_on_rails/prender_error_spec.rb +++ b/spec/react_on_rails/prender_error_spec.rb @@ -45,5 +45,32 @@ module ReactOnRails expect(expected_error.raven_context).to eq(expected_error_info) end end + + describe "error message formatting" do + context "when FULL_TEXT_ERRORS is true" do + before { ENV["FULL_TEXT_ERRORS"] = "true" } + after { ENV["FULL_TEXT_ERRORS"] = nil } + + it "shows the full backtrace" do + message = expected_error.message + expect(message).to include(err.inspect) + expect(message).to include(err.backtrace.join("\n")) + expect(message).not_to include("The rest of the backtrace is hidden") + end + end + + context "when FULL_TEXT_ERRORS is not set" do + before { ENV["FULL_TEXT_ERRORS"] = nil } + + it "shows truncated backtrace with notice" do + message = expected_error.message + expect(message).to include(err.inspect) + expect(message).to include( + "spec/react_on_rails/prender_error_spec.rb:20:in `block (2 levels) in '" + ) + expect(message).to include("The rest of the backtrace is hidden") + end + end + end end end diff --git a/spec/react_on_rails/utils_spec.rb b/spec/react_on_rails/utils_spec.rb index a9ecbfa4da..b8158a4c66 100644 --- a/spec/react_on_rails/utils_spec.rb +++ b/spec/react_on_rails/utils_spec.rb @@ -310,30 +310,47 @@ module ReactOnRails end describe ".smart_trim" do - it "trims smartly" do - s = "1234567890" - - expect(described_class.smart_trim(s, -1)).to eq("1234567890") - expect(described_class.smart_trim(s, 0)).to eq("1234567890") - expect(described_class.smart_trim(s, 1)).to eq("1#{Utils::TRUNCATION_FILLER}") - expect(described_class.smart_trim(s, 2)).to eq("1#{Utils::TRUNCATION_FILLER}0") - expect(described_class.smart_trim(s, 3)).to eq("1#{Utils::TRUNCATION_FILLER}90") - expect(described_class.smart_trim(s, 4)).to eq("12#{Utils::TRUNCATION_FILLER}90") - expect(described_class.smart_trim(s, 5)).to eq("12#{Utils::TRUNCATION_FILLER}890") - expect(described_class.smart_trim(s, 6)).to eq("123#{Utils::TRUNCATION_FILLER}890") - expect(described_class.smart_trim(s, 7)).to eq("123#{Utils::TRUNCATION_FILLER}7890") - expect(described_class.smart_trim(s, 8)).to eq("1234#{Utils::TRUNCATION_FILLER}7890") - expect(described_class.smart_trim(s, 9)).to eq("1234#{Utils::TRUNCATION_FILLER}67890") - expect(described_class.smart_trim(s, 10)).to eq("1234567890") - expect(described_class.smart_trim(s, 11)).to eq("1234567890") + let(:long_string) { "1234567890" } + + context "when FULL_TEXT_ERRORS is true" do + before { ENV["FULL_TEXT_ERRORS"] = "true" } + after { ENV["FULL_TEXT_ERRORS"] = nil } + + it "returns the full string regardless of length" do + expect(described_class.smart_trim(long_string, 5)).to eq(long_string) + end + + it "handles a hash without trimming" do + hash = { a: long_string } + expect(described_class.smart_trim(hash, 5)).to eq(hash.to_s) + end end - it "trims handles a hash" do - s = { a: "1234567890" } + context "when FULL_TEXT_ERRORS is not set" do + before { ENV["FULL_TEXT_ERRORS"] = nil } + + it "trims smartly" do + expect(described_class.smart_trim(long_string, -1)).to eq("1234567890") + expect(described_class.smart_trim(long_string, 0)).to eq("1234567890") + expect(described_class.smart_trim(long_string, 1)).to eq("1#{Utils::TRUNCATION_FILLER}") + expect(described_class.smart_trim(long_string, 2)).to eq("1#{Utils::TRUNCATION_FILLER}0") + expect(described_class.smart_trim(long_string, 3)).to eq("1#{Utils::TRUNCATION_FILLER}90") + expect(described_class.smart_trim(long_string, 4)).to eq("12#{Utils::TRUNCATION_FILLER}90") + expect(described_class.smart_trim(long_string, 5)).to eq("12#{Utils::TRUNCATION_FILLER}890") + expect(described_class.smart_trim(long_string, 6)).to eq("123#{Utils::TRUNCATION_FILLER}890") + expect(described_class.smart_trim(long_string, 7)).to eq("123#{Utils::TRUNCATION_FILLER}7890") + expect(described_class.smart_trim(long_string, 8)).to eq("1234#{Utils::TRUNCATION_FILLER}7890") + expect(described_class.smart_trim(long_string, 9)).to eq("1234#{Utils::TRUNCATION_FILLER}67890") + expect(described_class.smart_trim(long_string, 10)).to eq("1234567890") + expect(described_class.smart_trim(long_string, 11)).to eq("1234567890") + end - expect(described_class.smart_trim(s, 9)).to eq( - "{:a=#{Utils::TRUNCATION_FILLER}890\"}" - ) + it "trims handles a hash" do + s = { a: "1234567890" } + expect(described_class.smart_trim(s, 9)).to eq( + "{:a=#{Utils::TRUNCATION_FILLER}890\"}" + ) + end end end