diff --git a/lib/minitest.rb b/lib/minitest.rb index 71424cfa..1e7f63e7 100644 --- a/lib/minitest.rb +++ b/lib/minitest.rb @@ -836,8 +836,24 @@ def error # :nodoc: end def message # :nodoc: - bt = Minitest.filter_backtrace(self.backtrace).join "\n " - "#{self.exception.class}: #{self.exception.message}\n #{bt}" + if self.exception.respond_to?(:cause) && self.exception.cause + # Build a chain of exception causes starting from the outermost + exc = self.exception + cause_chain = [] + while exc + cause_chain.push(exc) + exc = exc.cause + end + + bt_lines = cause_chain.map { |c| + [c.message] + Minitest.filter_backtrace(c.backtrace) + }.inject() { |acc, bt| acc + ["...Caused By..."] + bt } + bt_out = bt_lines.join "\n " + "#{self.exception.class}: #{self.exception.message}\n #{bt_out}" + else + bt = Minitest.filter_backtrace(self.backtrace).join "\n " + "#{self.exception.class}: #{self.exception.message}\n #{bt}" + end end def result_label # :nodoc: diff --git a/test/minitest/test_minitest_test.rb b/test/minitest/test_minitest_test.rb index bfdd02e5..a73dbf15 100644 --- a/test/minitest/test_minitest_test.rb +++ b/test/minitest/test_minitest_test.rb @@ -263,6 +263,40 @@ def test_error assert_report expected end + def test_run_nested_error + @tu = + Class.new FakeNamedTest do + def test_something + assert true + end + + def test_error + begin + raise "internal exception" + rescue + raise "external exception" + end + end + end + + expected = clean <<-EOM + E. + + Finished in 0.00 + + 1) Error: + FakeNamedTestXX#test_error: + RuntimeError: external exception + FILE:LINE:in \`rescue in test_error\' + FILE:LINE:in \`test_error\' + FILE:LINE:in \`test_error\' + + 2 runs, 1 assertions, 0 failures, 1 errors, 0 skips + EOM + + assert_report expected + end + def test_run_error_teardown @tu = Class.new FakeNamedTest do