From f047f57530f186a4047600fd7c3a5943f86d87e5 Mon Sep 17 00:00:00 2001 From: Cliff Pruitt Date: Fri, 15 Mar 2019 11:43:39 -0400 Subject: [PATCH] Allow assert_template(file:) to work using Rails 6 An `ActionView::Template`'s `virtual_path` is deprecated under Rails 6. This commit: https://github.com/rails/rails/commit/9a343d148b96874a231b87906c9d6499b5e0b64a#diff-40f2a5bcf9edfd65a8efe42a05c53736L437 causes the virtual path for templates rendered using `file:` to no longer have their `virtual_path` explicitly set to nil. `rails-controller-testing` uses the absence of the `virtual_path` attribute to indicate that the template was rendered as using `file:`. See: https://github.com/rails/rails-controller-testing/blob/master/lib/rails/controller/testing/template_assertions.rb#L34 Because the attribute is never nil with Rails 6, the ability to test something like `assert_template(file: "#{Rails.root}/public/404.html")` is broken. This commit changes the way rendered `file:` templates are tracked. Instead of paying attention calls to `ActionView::Template#render` ( subscribing to`"!render_template.action_view"`) this update instead focuses on `ActionView::TemplateRenderer#determine_template`. Because `determine_tempalte` is not already instrumented, we need to provide our own instrumentation by redefining the method, adding instrumentation, and then handing off to `super`. --- lib/rails/controller/testing.rb | 4 ++++ .../controller/testing/template_assertions.rb | 16 ++++++++++------ .../testing/template_instrumentation.rb | 16 ++++++++++++++++ 3 files changed, 30 insertions(+), 6 deletions(-) create mode 100644 lib/rails/controller/testing/template_instrumentation.rb diff --git a/lib/rails/controller/testing.rb b/lib/rails/controller/testing.rb index 45a2b27..7b2d0fc 100644 --- a/lib/rails/controller/testing.rb +++ b/lib/rails/controller/testing.rb @@ -2,6 +2,7 @@ require 'rails/controller/testing/test_process' require 'rails/controller/testing/integration' require 'rails/controller/testing/template_assertions' +require 'rails/controller/testing/template_instrumentation' module Rails module Controller @@ -10,16 +11,19 @@ def self.install ActiveSupport.on_load(:action_controller_test_case) do include Rails::Controller::Testing::TestProcess include Rails::Controller::Testing::TemplateAssertions + ActionView::TemplateRenderer.prepend(InstrumentDetermineTemplate) end ActiveSupport.on_load(:action_dispatch_integration_test) do include Rails::Controller::Testing::TemplateAssertions include Rails::Controller::Testing::Integration include Rails::Controller::Testing::TestProcess + ActionView::TemplateRenderer.prepend(InstrumentDetermineTemplate) end ActiveSupport.on_load(:action_view_test_case) do include Rails::Controller::Testing::TemplateAssertions + ActionView::TemplateRenderer.prepend(InstrumentDetermineTemplate) end end end diff --git a/lib/rails/controller/testing/template_assertions.rb b/lib/rails/controller/testing/template_assertions.rb index ad5e8ad..dcf8b1f 100644 --- a/lib/rails/controller/testing/template_assertions.rb +++ b/lib/rails/controller/testing/template_assertions.rb @@ -30,6 +30,16 @@ def setup_subscriptions end end + @_subscribers << ActiveSupport::Notifications.subscribe("determine_template.rails_controller_testing") do |_name, _start, _finish, _id, payload| + if payload[:options][:file] + path = payload[:template_identifier] + if path + @_files[path] += 1 + @_files[path.split("/").last] += 1 + end + end + end + @_subscribers << ActiveSupport::Notifications.subscribe("!render_template.action_view") do |_name, _start, _finish, _id, payload| if virtual_path = payload[:virtual_path] partial = virtual_path =~ /^.*\/_[^\/]*$/ @@ -40,12 +50,6 @@ def setup_subscriptions end @_templates[virtual_path] += 1 - else - path = payload[:identifier] - if path - @_files[path] += 1 - @_files[path.split("/").last] += 1 - end end end end diff --git a/lib/rails/controller/testing/template_instrumentation.rb b/lib/rails/controller/testing/template_instrumentation.rb new file mode 100644 index 0000000..08cdc27 --- /dev/null +++ b/lib/rails/controller/testing/template_instrumentation.rb @@ -0,0 +1,16 @@ +module Rails + module Controller + module Testing + module InstrumentDetermineTemplate + def determine_template(options) + super.tap do |found| + if found + instrument_payload = { template_identifier: found.identifier, virtual_path: found.virtual_path, options: options } + ActiveSupport::Notifications.instrument("determine_template.rails_controller_testing", instrument_payload) + end + end + end + end + end + end +end \ No newline at end of file