Skip to content

Commit

Permalink
Merge pull request #453 from BetterErrors/fix/shortval-assertion-shou…
Browse files Browse the repository at this point in the history
…ld-fail

Fix various specs that were passing incorrectly
  • Loading branch information
RobinDaugherty committed Feb 26, 2020
2 parents c18a975 + 64e65fa commit c24c87f
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 37 deletions.
1 change: 1 addition & 0 deletions better_errors.gemspec
Expand Up @@ -22,6 +22,7 @@ Gem::Specification.new do |s|

s.add_development_dependency "rake", "~> 10.0"
s.add_development_dependency "rspec", "~> 3.5"
s.add_development_dependency "rspec-html-matchers"
s.add_development_dependency "rspec-its"
s.add_development_dependency "yard"
# kramdown 2.1 requires Ruby 2.3+
Expand Down
102 changes: 65 additions & 37 deletions spec/better_errors/error_page_spec.rb
Expand Up @@ -2,6 +2,11 @@

module BetterErrors
describe ErrorPage do
# It's necessary to use HTML matchers here that are specific as possible.
# This is because if there's an exception within this file, the lines of code will be reflected in the
# generated HTML, so any strings being matched against the HTML content will be there if they're within 5
# lines of code of the exception that was raised.

let!(:exception) { raise ZeroDivisionError, "you divided by zero you silly goose!" rescue $! }

let(:error_page) { ErrorPage.new exception, { "PATH_INFO" => "/some/path" } }
Expand All @@ -19,44 +24,53 @@ module BetterErrors
}

it "includes the error message" do
expect(response).to include("you divided by zero you silly goose!")
expect(response).to have_tag('.exception p', text: /you divided by zero you silly goose!/)
end

it "includes the request path" do
expect(response).to include("/some/path")
expect(response).to have_tag('.exception h2', %r{/some/path})
end

it "includes the exception class" do
expect(response).to include("ZeroDivisionError")
expect(response).to have_tag('.exception h2', /ZeroDivisionError/)
end

context "variable inspection" do
let(:exception) { exception_binding.eval("raise") rescue $! }

if BetterErrors.binding_of_caller_available?
context "when binding_of_caller is loaded" do
before do
skip "binding_of_caller is not loaded" unless BetterErrors.binding_of_caller_available?
end

it "shows local variables" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include('<td class="name">local_a</td>')
expect(html).to include("<pre>:value_for_local_a</pre>")
expect(html).to include('<td class="name">local_b</td>')
expect(html).to include("<pre>:value_for_local_b</pre>")
expect(html).to have_tag('div.variables') do
with_tag('td.name', text: 'local_a')
with_tag('pre', text: ':value_for_local_a')
with_tag('td.name', text: 'local_b')
with_tag('pre', text: ':value_for_local_b')
end
end

it "shows instance variables" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include('<td class="name">' + '@inst_c</td>')
expect(html).to include("<pre>" + ":value_for_inst_c</pre>")
expect(html).to include('<td class="name">' + '@inst_d</td>')
expect(html).to include("<pre>" + ":value_for_inst_d</pre>")
expect(html).to have_tag('div.variables') do
with_tag('td.name', text: '@inst_c')
with_tag('pre', text: ':value_for_inst_c')
with_tag('td.name', text: '@inst_d')
with_tag('pre', text: ':value_for_inst_d')
end
end

it "does not show filtered variables" do
allow(BetterErrors).to receive(:ignored_instance_variables).and_return([:@inst_d])
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include('<td class="name">' + '@inst_c</td>')
expect(html).to include("<pre>" + ":value_for_inst_c</pre>")
expect(html).not_to include('<td class="name">' + '@inst_d</td>')
expect(html).not_to include("<pre>" + ":value_for_inst_d</pre>")
expect(html).to have_tag('div.variables') do
with_tag('td.name', text: '@inst_c')
with_tag('pre', text: ':value_for_inst_c')
end
expect(html).not_to have_tag('div.variables td.name', text: '@inst_d')
end

context 'when maximum_variable_inspect_size is set' do
Expand All @@ -79,7 +93,7 @@ module BetterErrors

it "shows the variable content" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include(content)
expect(html).to have_tag('div.variables', text: %r{#{content}})
end
end

Expand All @@ -99,12 +113,12 @@ def inspect
"shortval"
end
end
InspectableTestValue.new
ExtremelyLargeInspectableTestValue.new
}

it "shows the variable content" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include("shortval")
expect(html).to have_tag('div.variables', text: /shortval/)
end
end
context 'and does not implement #inspect' do
Expand All @@ -117,8 +131,8 @@ def inspect

it "includes an indication that the variable was too large" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to_not include(content)
expect(html).to include("Object too large")
expect(html).not_to have_tag('div.variables', text: %r{#{content}})
expect(html).to have_tag('div.variables', text: /Object too large/)
end
end

Expand All @@ -135,13 +149,16 @@ def initialize

it "does not attempt to show the class name" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include('<td class="name">' + '@big_anonymous</td>')
expect(html).to include('Object too large')
expect(html).to include('Adjust BetterErrors.maximum_variable_inspect_size')
expect(html).to have_tag('div.variables') do
with_tag('td.name', text: '@big_anonymous')
with_tag('.unsupported', text: /Object too large/)
with_tag('.unsupported', text: /Adjust BetterErrors.maximum_variable_inspect_size/)
end
end
end
end
end

context 'on a platform without ObjectSpace' do
before do
Object.send(:remove_const, :ObjectSpace) if Object.constants.include?(:ObjectSpace)
Expand All @@ -160,7 +177,7 @@ def initialize

it "shows the variable content" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include(content)
expect(html).to have_tag('div.variables', text: %r{#{content}})
end
end

Expand All @@ -180,12 +197,12 @@ def inspect
"shortval"
end
end
InspectableTestValue.new
ExtremelyLargeInspectableTestValue.new
}

it "shows the variable content" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include("shortval")
expect(html).to have_tag('div.variables', text: /shortval/)
end
end
context 'and does not implement #inspect' do
Expand All @@ -197,9 +214,10 @@ def inspect
let(:content) { 'A' * 1101 }

it "includes an indication that the variable was too large" do

html = error_page.do_variables("index" => 0)[:html]
expect(html).to_not include(content)
expect(html).to include("Object too large")
expect(html).not_to have_tag('div.variables', text: %r{#{content}})
expect(html).to have_tag('div.variables', text: /Object too large/)
end
end
end
Expand All @@ -217,9 +235,11 @@ def initialize

it "does not attempt to show the class name" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include('<td class="name">' + '@big_anonymous</td>')
expect(html).to include('Object too large')
expect(html).to include('Adjust BetterErrors.maximum_variable_inspect_size')
expect(html).to have_tag('div.variables') do
with_tag('td.name', text: '@big_anonymous')
with_tag('.unsupported', text: /Object too large/)
with_tag('.unsupported', text: /Adjust BetterErrors.maximum_variable_inspect_size/)
end
end
end
end
Expand All @@ -239,23 +259,30 @@ def initialize

it "includes the content of large variables" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include(content)
expect(html).to_not include("Object too large")
expect(html).to have_tag('div.variables', text: %r{#{content}})
expect(html).not_to have_tag('div.variables', text: /Object too large/)
end
end
else
end

context "when binding_of_caller is not loaded" do
before do
skip "binding_of_caller is loaded" if BetterErrors.binding_of_caller_available?
end

it "tells the user to add binding_of_caller to their gemfile to get fancy features" do
html = error_page.do_variables("index" => 0)[:html]
expect(html).to include(%{gem "binding_of_caller"})
expect(html).not_to have_tag('div.variables', text: /gem "binding_of_caller"/)
end
end
end

it "doesn't die if the source file is not a real filename" do
allow(exception).to receive(:__better_errors_bindings_stack).and_return([])
allow(exception).to receive(:backtrace).and_return([
"<internal:prelude>:10:in `spawn_rack_application'"
])
expect(response).to include("Source unavailable")
expect(response).to have_tag('.frames li .location .filename', text: '<internal:prelude>')
end

context 'with an exception with blank lines' do
Expand Down Expand Up @@ -299,6 +326,7 @@ def initialize(message = nil)
)
end
end

context 'with binding_of_caller available' do
before do
skip("Disabled without binding_of_caller") unless defined? ::BindingOfCaller
Expand Down
6 changes: 6 additions & 0 deletions spec/spec_helper.rb
Expand Up @@ -19,3 +19,9 @@

require 'bundler/setup'
Bundler.require(:default)

require 'rspec-html-matchers'

RSpec.configure do |config|
config.include RSpecHtmlMatchers
end

0 comments on commit c24c87f

Please sign in to comment.