Skip to content

Commit

Permalink
Merge pull request #51093 from seanpdoyle/action-view-rendered-memoiz…
Browse files Browse the repository at this point in the history
…ation

Action View Test Case `rendered` memoization
  • Loading branch information
eugeneius committed Feb 15, 2024
2 parents dd6f3e1 + 01502fe commit 9aeb1de
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 29 deletions.
10 changes: 5 additions & 5 deletions actionview/lib/action_view/test_case.rb
Expand Up @@ -60,7 +60,7 @@ module Behavior
include ActiveSupport::Testing::ConstantLookup

delegate :lookup_context, to: :controller
attr_accessor :controller, :request, :output_buffer
attr_accessor :controller, :request, :output_buffer, :rendered

module ClassMethods
def inherited(descendant) # :nodoc:
Expand Down Expand Up @@ -223,7 +223,7 @@ def setup_with_controller
@request = @controller.request
@view_flow = ActionView::OutputFlow.new
@output_buffer = ActionView::OutputBuffer.new
@rendered = +""
@rendered = self.class.content_class.new(+"")

test_case_instance = self
controller_class.define_method(:_test_case) { test_case_instance }
Expand All @@ -243,6 +243,9 @@ def rendered_views
@_rendered_views ||= RenderedViewsCollection.new
end

##
# :method: rendered
#
# Returns the content rendered by the last +render+ call.
#
# The returned object behaves like a string but also exposes a number of methods
Expand Down Expand Up @@ -290,9 +293,6 @@ def rendered_views
#
# assert_pattern { rendered.json => { title: "Hello, world" } }
# end
def rendered
@_rendered ||= self.class.content_class.new(@rendered)
end

def _routes
@controller._routes if @controller.respond_to?(:_routes)
Expand Down
20 changes: 20 additions & 0 deletions actionview/test/template/test_case_test.rb
Expand Up @@ -394,6 +394,26 @@ class RenderedViewContentTest < ActionView::TestCase
assert_match(/#{developer.name}/, rendered)
assert_includes rendered, developer.name
end

test "#rendered resets after each render" do
render "developers/developer", developer: DeveloperStruct.new("first")

assert_includes rendered, "first"
assert_not_includes rendered, "second"
assert_not_includes rendered, "third"

render "developers/developer", developer: DeveloperStruct.new("second")

assert_includes rendered, "first"
assert_includes rendered, "second"
assert_not_includes rendered, "third"

render "developers/developer", developer: DeveloperStruct.new("third")

assert_includes rendered, "first"
assert_includes rendered, "second"
assert_includes rendered, "third"
end
end

class HTMLParserTest < ActionView::TestCase
Expand Down
24 changes: 0 additions & 24 deletions guides/source/upgrading_ruby_on_rails.md
Expand Up @@ -283,30 +283,6 @@ const fileInputSelector = Rails.fileInputSelector
Rails.fileInputSelector(...)
```

### `ActionView::TestCase#rendered` no longer returns a `String`

Starting from Rails 7.1, `ActionView::TestCase#rendered` returns an object that
responds to various format methods (for example, `rendered.html` and
`rendered.json`). To preserve backward compatibility, the object returned from
`rendered` will delegate missing methods to the `String` rendered during the
test. For example, the following [assert_match][] assertion will pass:

```ruby
assert_match(/some content/i, rendered)
```

However, if your tests rely on `ActionView::TestCase#rendered` returning an
instance of `String`, they will fail. To restore the original behavior, you can
override the `#rendered` method to read from the `@rendered` instance variable:

```ruby
# config/initializers/action_view.rb

ActiveSupport.on_load :action_view_test_case do
attr_reader :rendered
end
```

### `Rails.logger` now returns an `ActiveSupport::BroadcastLogger` instance

The `ActiveSupport::BroadcastLogger` class is a new logger that allows to broadcast logs to different sinks (STDOUT, a log file...) in an easy way.
Expand Down

0 comments on commit 9aeb1de

Please sign in to comment.