Skip to content

Commit 32e3634

Browse files
authored
Add custom inspection for ActionDispatch::Request (#294)
Fixes #160. Per investigation detailed on that issue, the default object inspection tree builder recursively works through all `ActionDispatch::Request` instance variables. This includes `env`, which can have enormous values, including and especially the app's entire route set. Since the Rails code itself customizes inspection for this class, we'll do the same here.
1 parent 6a49f04 commit 32e3634

File tree

11 files changed

+221
-2
lines changed

11 files changed

+221
-2
lines changed

lib/super_diff/action_dispatch.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# frozen_string_literal: true
2+
3+
require 'super_diff/action_dispatch/inspection_tree_builders'
4+
5+
module SuperDiff
6+
module ActionDispatch
7+
SuperDiff.configure do |config|
8+
config.prepend_extra_inspection_tree_builder_classes(
9+
InspectionTreeBuilders::Request
10+
)
11+
end
12+
end
13+
end
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# frozen_string_literal: true
2+
3+
module SuperDiff
4+
module ActionDispatch
5+
module InspectionTreeBuilders
6+
autoload(
7+
:Request,
8+
'super_diff/action_dispatch/inspection_tree_builders/request'
9+
)
10+
end
11+
end
12+
end
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# frozen_string_literal: true
2+
3+
module SuperDiff
4+
module ActionDispatch
5+
module InspectionTreeBuilders
6+
class Request < Core::AbstractInspectionTreeBuilder
7+
def self.applies_to?(value)
8+
value.is_a?(::ActionDispatch::Request)
9+
end
10+
11+
def call
12+
Core::InspectionTree.new do |t1|
13+
t1.as_lines_when_rendering_to_lines do |t2|
14+
t2.add_text object.inspect
15+
end
16+
end
17+
end
18+
end
19+
end
20+
end
21+
end

lib/super_diff/rails.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22

33
require 'super_diff/active_support'
44
require 'super_diff/active_record' if defined?(ActiveRecord)
5+
require 'super_diff/action_dispatch' if defined?(ActionDispatch)
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
RSpec.describe 'Integration with ActionDispatch', type: :integration, action_dispatch: true do
6+
context "when using 'super_diff/rspec-rails'" do
7+
include_context 'integration with ActionDispatch'
8+
9+
def make_program(test, color_enabled:)
10+
make_rspec_rails_test_program(test, color_enabled: color_enabled)
11+
end
12+
end
13+
14+
context "when using 'super_diff/action_dispatch'" do
15+
include_context 'integration with ActionDispatch'
16+
17+
def make_program(test, color_enabled:)
18+
make_rspec_action_dispatch_program(test, color_enabled: color_enabled)
19+
end
20+
end
21+
end

spec/spec_helper.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
active_record_available = false
2626
end
2727

28+
begin
29+
require 'action_dispatch'
30+
rescue LoadError
31+
# ActionDispatch isn't available (presumably because we're not testing it)
32+
end
33+
2834
Dir
2935
.glob(File.expand_path('support/**/*.rb', __dir__))
3036
.reject { |file| file.include?('/models/active_record/') && !active_record_available }
@@ -52,6 +58,7 @@
5258
config.default_formatter = 'documentation' unless %w[true 1].include?(ENV.fetch('CI', nil))
5359

5460
config.filter_run_excluding active_record: true unless active_record_available
61+
config.filter_run_excluding action_dispatch: true unless defined?(ActionDispatch)
5562
config.filter_run_excluding active_support: true unless defined?(ActiveSupport)
5663
config.filter_run_excluding with_superdiff_rspec: false
5764

spec/support/integration/helpers.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ def make_rspec_active_support_program(test, color_enabled:)
3030
TestPrograms::RSpecActiveSupport.new(test, color_enabled: color_enabled)
3131
end
3232

33+
def make_rspec_action_dispatch_program(test, color_enabled:)
34+
TestPrograms::RSpecActionDispatch.new(test, color_enabled: color_enabled)
35+
end
36+
3337
def make_rspec_rails_test_program(test, color_enabled:)
3438
TestPrograms::RSpecRails.new(test, color_enabled: color_enabled)
3539
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
module SuperDiff
4+
module IntegrationTests
5+
module TestPrograms
6+
class RSpecActionDispatch < Base
7+
protected
8+
9+
def test_plan_prelude
10+
<<~PRELUDE.strip
11+
test_plan.boot
12+
test_plan.boot_action_dispatch
13+
PRELUDE
14+
end
15+
16+
def test_plan_command
17+
'run_rspec_action_dispatch_test'
18+
end
19+
end
20+
end
21+
end
22+
end
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# frozen_string_literal: true
2+
3+
shared_examples_for 'integration with ActionDispatch' do
4+
context 'when testing attributes of an ActionDispatch::TestResponse' do
5+
it 'produces the correct failure message when used in the positive' do
6+
as_both_colored_and_uncolored do |color_enabled|
7+
snippet = <<~RUBY
8+
request = ActionDispatch::TestRequest.create
9+
response = ActionDispatch::TestResponse.new(200, {}, []).tap do |response|
10+
response.request = request
11+
end
12+
13+
# The other attributes of TestResponse differ across Rails versions. We don't care about them
14+
# for the purposes of this test.
15+
ActionDispatch::TestResponse.define_method(:attributes_for_super_diff) { {request: request} }
16+
17+
expect(response).to be_bad_request
18+
RUBY
19+
program =
20+
make_rspec_action_dispatch_program(snippet, color_enabled: color_enabled)
21+
22+
expected_output =
23+
build_expected_output(
24+
color_enabled: color_enabled,
25+
snippet: 'expect(response).to be_bad_request',
26+
newline_before_expectation: true,
27+
expectation:
28+
proc do
29+
line do
30+
plain ' Expected '
31+
actual '#<ActionDispatch::TestResponse request: #<ActionDispatch::TestRequest GET "http://test.host/" for 0.0.0.0>>'
32+
end
33+
34+
line do
35+
plain 'to return a truthy result for '
36+
expected 'bad_request?'
37+
plain ' or '
38+
expected 'bad_requests?'
39+
end
40+
end
41+
)
42+
43+
expect(program).to produce_output_when_run(expected_output).in_color(
44+
color_enabled
45+
)
46+
end
47+
end
48+
end
49+
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
5+
RSpec.describe SuperDiff, type: :unit do
6+
describe '.inspect_object', 'for ActionDispatch objects', action_dispatch: true do
7+
context 'given an ActionDispatch::Request' do
8+
context 'given as_lines: false' do
9+
it 'returns an inspected version of the object' do
10+
string =
11+
described_class.inspect_object(
12+
ActionDispatch::Request.new(
13+
{
14+
'REQUEST_METHOD' => 'PUT',
15+
'REMOTE_ADDR' => '10.0.0.1',
16+
Rack::RACK_URL_SCHEME => 'http',
17+
'HTTP_HOST' => 'host.local'
18+
}
19+
),
20+
as_lines: false
21+
)
22+
expect(string).to eq(
23+
%(#<ActionDispatch::Request PUT "http://host.local" for 10.0.0.1>)
24+
)
25+
end
26+
end
27+
28+
context 'given as_lines: true' do
29+
it 'returns an inspected version of the object on one line' do
30+
tiered_lines =
31+
described_class.inspect_object(
32+
ActionDispatch::Request.new(
33+
{
34+
'REQUEST_METHOD' => 'PUT',
35+
'REMOTE_ADDR' => '10.0.0.1',
36+
Rack::RACK_URL_SCHEME => 'http',
37+
'HTTP_HOST' => 'host.local'
38+
}
39+
),
40+
as_lines: true,
41+
type: :noop,
42+
indentation_level: 1
43+
)
44+
45+
expect(tiered_lines).to match(
46+
[
47+
an_object_having_attributes(
48+
type: :noop,
49+
indentation_level: 1,
50+
value: '#<ActionDispatch::Request PUT "http://host.local" for 10.0.0.1>'
51+
)
52+
]
53+
)
54+
end
55+
end
56+
end
57+
end
58+
end

0 commit comments

Comments
 (0)