Skip to content

Commit bec8037

Browse files
committed
Parse ActionView::TestCase#rendered as DocumentFragment
To integrate with [rails-dom-testing][] and its selector assertions, `ActionView::TestCase` [defines a `#document_root_element` method][document_root_element] that parses the HTML into a fully valid HTML document and returns the "root". In the case of most Action View partials rendered with `render partial: "..."`, the resulting document would be invalid, so its constituent parts (its `<html>`, `<head>`, and `<body>` elements) are synthesized in during the parsing process. This results in a document whose _contents_ are equivalent to the original HTML string, but whose structure is not. To share a concrete example: ```ruby irb(main):002:0> rendered = "<h1>Hello world</h1><h2>Goodbye world</h2>" => "<h1>Hello world</h1><h2>Goodbye world</h2>" irb(main):003:0> root = Rails::Dom::Testing.html_document.parse(rendered).root => #(Element:0x57080 { ... irb(main):004:0> rendered.to_s => "<h1>Hello world</h1><h2>Goodbye world</h2>" irb(main):005:0> root.to_s => "<html><head></head><body><h1>Hello world</h1><h2>Goodbye world</h2></body></html>" irb(main):006:0> rendered.to_s == root.to_s => false ``` Prior to this commit, the parsed HTML content returned from calling `rendered.html` relied on the same mechanisms as `#document_root_element`, and parsed the HTML fragment into a full document, with a synthesized `<html>` element as its root. The `rendered.html` value should reflect the content that was **rendered** by the partial, and should not behave the same as `#document_root_element`. When the parsing class is changed from [Nokogiri::XML::Document][] to [Nokogiri::XML::DocumentFragment][], the returned value reflects the same **exact** content as what was rendered. To elaborate on the previous example: ```ruby irb(main):007:0> fragment = Rails::Dom::Testing.html_document_fragment.parse(rendered) => #(DocumentFragment:0x62ee4 { ... irb(main):008:0> fragment.to_s => "<h1>Hello world</h1><h2>Goodbye world</h2>" irb(main):009:0> rendered.to_s == fragment.to_s => true ``` This commit changes the default `rendered.html` behavior to rely on `Nokogiri::XML::DocumentFragment` instead of `Nokogiri::XML::Document`. [Nokogiri::XML::Document]: https://nokogiri.org/rdoc/Nokogiri/XML/Document.html [Nokogiri::XML::DocumentFragment]: https://nokogiri.org/rdoc/Nokogiri/XML/DocumentFragment.html [document_root_element]: https://github.com/rails/rails-dom-testing/blob/v2.2.0/lib/rails/dom/testing/assertions/selector_assertions.rb#L75
1 parent 4d2beb7 commit bec8037

File tree

3 files changed

+9
-3
lines changed

3 files changed

+9
-3
lines changed

actionview/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
* Parse `ActionView::TestCase#rendered` HTML content as `Nokogiri::XML::DocumentFragment` instead of `Nokogiri::XML::Document`
2+
3+
*Sean Doyle*
4+
15
* Rename `ActionView::TestCase::Behavior::{Content,RenderedViewContent}`
26

37
*Sean Doyle*

actionview/lib/action_view/test_case.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ def include_helper_modules!
202202

203203
setup :setup_with_controller
204204

205-
register_parser :html, -> rendered { Rails::Dom::Testing.html_document.parse(rendered).root }
205+
register_parser :html, -> rendered { Rails::Dom::Testing.html_document_fragment.parse(rendered) }
206206
register_parser :json, -> rendered { JSON.parse(rendered, object_class: ActiveSupport::HashWithIndifferentAccess) }
207207

208208
ActiveSupport.run_load_hooks(:action_view_test_case, self)

actionview/test/template/test_case_test.rb

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -397,12 +397,13 @@ class RenderedViewContentTest < ActionView::TestCase
397397
end
398398

399399
class HTMLParserTest < ActionView::TestCase
400-
test "rendered.html is a Nokogiri::XML::Element" do
400+
test "rendered.html is a Nokogiri::XML::DocumentFragment" do
401401
developer = DeveloperStruct.new("Eloy")
402402

403403
render "developers/developer", developer: developer
404404

405-
assert_kind_of Nokogiri::XML::Element, rendered.html
405+
assert_kind_of Nokogiri::XML::DocumentFragment, rendered.html
406+
assert_equal rendered.to_s, rendered.html.to_s
406407
assert_equal developer.name, document_root_element.text
407408
end
408409

@@ -425,6 +426,7 @@ class JSONParserTest < ActionView::TestCase
425426
render formats: :json, partial: "developers/developer", locals: { developer: developer }
426427

427428
assert_kind_of ActiveSupport::HashWithIndifferentAccess, rendered.json
429+
assert_equal rendered.to_s, rendered.json.to_json
428430
assert_equal developer.name, rendered.json[:name]
429431
end
430432
end

0 commit comments

Comments
 (0)