Skip to content

Commit ce7e1cf

Browse files
authored
Merge pull request #2714 from rspec/fix-stub-template
Prevent `stub_template` from leaking between view specs
2 parents 6c89ad4 + 52898ce commit ce7e1cf

File tree

5 files changed

+73
-33
lines changed

5 files changed

+73
-33
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
TEMPLATE_HTML

example_app_generator/generate_stuff.rb

+2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ def setup_tasks
1414

1515
def final_tasks
1616
copy_file 'spec/verify_active_record_spec.rb'
17+
copy_file 'app/views/_example.html.erb'
1718
copy_file 'app/views/foo.html'
1819
copy_file 'app/views/some_templates/bar.html'
1920
copy_file 'spec/verify_custom_renderers_spec.rb'
2021
copy_file 'spec/verify_fixture_warning_spec.rb'
22+
copy_file 'spec/verify_view_path_stub_spec.rb'
2123
run('bin/rake db:migrate')
2224
end
2325

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
require 'rails_helper'
2+
3+
RSpec.describe "verify view path doesnt leak stubs between examples", type: :view, order: :defined do
4+
subject(:html) do
5+
render partial: "example"
6+
rendered
7+
end
8+
9+
it "renders the stub template" do
10+
stub_template("_example.html.erb" => "STUB_HTML")
11+
expect(html).to include("STUB_HTML")
12+
end
13+
14+
it "renders the file template" do
15+
expect(html).to include("TEMPLATE_HTML")
16+
end
17+
end

lib/rspec/rails/example/view_example_group.rb

+8-20
Original file line numberDiff line numberDiff line change
@@ -83,26 +83,14 @@ def view
8383
_view
8484
end
8585

86-
if ::Rails.version.to_f >= 7.1
87-
# Simulates the presence of a template on the file system by adding a
88-
# Rails' FixtureResolver to the front of the view_paths list. Designed to
89-
# help isolate view examples from partials rendered by the view template
90-
# that is the subject of the example.
91-
#
92-
# stub_template("widgets/_widget.html.erb" => "This content.")
93-
def stub_template(hash)
94-
view.view_paths.send(:initialize_copy, ActionView::PathSet.new([StubResolverCache.resolver_for(hash)] + view.view_paths.paths))
95-
end
96-
else
97-
# Simulates the presence of a template on the file system by adding a
98-
# Rails' FixtureResolver to the front of the view_paths list. Designed to
99-
# help isolate view examples from partials rendered by the view template
100-
# that is the subject of the example.
101-
#
102-
# stub_template("widgets/_widget.html.erb" => "This content.")
103-
def stub_template(hash)
104-
view.view_paths.unshift(StubResolverCache.resolver_for(hash))
105-
end
86+
# Simulates the presence of a template on the file system by adding a
87+
# Rails' FixtureResolver to the front of the view_paths list. Designed to
88+
# help isolate view examples from partials rendered by the view template
89+
# that is the subject of the example.
90+
#
91+
# stub_template("widgets/_widget.html.erb" => "This content.")
92+
def stub_template(hash)
93+
controller.prepend_view_path(StubResolverCache.resolver_for(hash))
10694
end
10795

10896
# Provides access to the params hash that will be available within the

spec/rspec/rails/example/view_example_group_spec.rb

+45-13
Original file line numberDiff line numberDiff line change
@@ -280,33 +280,65 @@ def _view; end
280280

281281
describe '#stub_template' do
282282
let(:view_spec_group) do
283-
Class.new do
284-
include ViewExampleGroup::ExampleMethods
285-
def _view
286-
@_view ||= Struct.new(:view_paths).new(ActionView::PathSet.new(['some-path']))
287-
end
283+
RSpec.describe "a view spec" do
284+
include ::RSpec::Rails::ViewExampleGroup
288285
end
289286
end
290287

291288
it 'prepends an ActionView::FixtureResolver to the view path' do
292-
view_spec = view_spec_group.new
293-
view_spec.stub_template('some_path/some_template' => 'stubbed-contents')
289+
result = :not_loaded
294290

295-
result = view_spec.view.view_paths.first
291+
view_spec_group.specify do
292+
stub_template('some_path/some_template' => 'stubbed-contents')
293+
result = view.view_paths.first
294+
end
295+
view_spec_group.run
296296

297297
expect(result).to be_instance_of(ActionView::FixtureResolver)
298298
data = result.respond_to?(:data) ? result.data : result.hash
299299
expect(data).to eq('some_path/some_template' => 'stubbed-contents')
300300
end
301301

302+
it 'caches FixtureResolver instances between examples' do
303+
example_one_view_paths = :not_set
304+
example_two_view_paths = :not_set
305+
306+
view_spec_group.specify do
307+
stub_template('some_path/some_template' => 'stubbed-contents')
308+
example_one_view_paths = view.view_paths
309+
end
310+
view_spec_group.specify do
311+
stub_template('some_path/some_template' => 'stubbed-contents')
312+
example_two_view_paths = view.view_paths
313+
end
314+
view_spec_group.run
315+
316+
expect(example_one_view_paths.first).to eq(example_two_view_paths.first)
317+
end
318+
302319
it 'caches FixtureResolver instances between example groups' do
303-
view_spec_one = view_spec_group.new
304-
view_spec_two = view_spec_group.new
320+
example_one_view_paths = :not_set
321+
example_two_view_paths = :not_set
305322

306-
view_spec_one.stub_template('some_path/some_template' => 'stubbed-contents')
307-
view_spec_two.stub_template('some_path/some_template' => 'stubbed-contents')
323+
RSpec.describe "a view spec" do
324+
include ::RSpec::Rails::ViewExampleGroup
325+
326+
specify do
327+
stub_template('some_path/some_template' => 'stubbed-contents')
328+
example_one_view_paths = view.view_paths
329+
end
330+
end.run
331+
332+
RSpec.describe "another view spec" do
333+
include ::RSpec::Rails::ViewExampleGroup
334+
335+
specify do
336+
stub_template('some_path/some_template' => 'stubbed-contents')
337+
example_two_view_paths = view.view_paths
338+
end
339+
end.run
308340

309-
expect(view_spec_one.view.view_paths.first).to eq(view_spec_two.view.view_paths.first)
341+
expect(example_one_view_paths.first).to eq(example_two_view_paths.first)
310342
end
311343
end
312344
end

0 commit comments

Comments
 (0)