Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix various specs that were passing incorrectly #453

Merged
merged 4 commits into from Feb 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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