mirror of https://github.com/rails/rails
`ActionDispatch::Testing::TestResponse#parsed_body` parse HTML with Nokogiri
Prior to this commit, the only out-of-the-box parsing that `ActionDispatch::Testing::TestResponse#parsed_body` supported was for `application/json` requests. This meant that `response.body == response.parsed_body` for HTML requests. ```ruby get "/posts" response.content_type # => "text/html; charset=utf-8" response.parsed_body.class # => Nokogiri::HTML5::Document response.parsed_body.to_html # => "<!DOCTYPE html>\n<html>\n..." ``` Using `parsed_body` for JSON requests supports `Hash#fetch`, `Hash#dig`, and Ruby 3.2 destructuring assignment and pattern matching. The introduction of [Nokogiri support for pattern matching][nokogiri-pattern-matching] poses an opportunity to make assertions about the structure of the HTML response. On top of that, there is ongoing work to [introduce pattern matching support in MiniTest][minitest-pattern-matching]. [nokogiri-pattern-matching]: https://github.com/sparklemotion/nokogiri/pull/2523 [minitest-pattern-matching]: https://github.com/minitest/minitest/pull/936
This commit is contained in:
parent
6b30c3f410
commit
ad79ed0e6b
|
@ -39,6 +39,7 @@ PATH
|
|||
actionpack (7.1.0.alpha)
|
||||
actionview (= 7.1.0.alpha)
|
||||
activesupport (= 7.1.0.alpha)
|
||||
nokogiri (>= 1.8.5)
|
||||
rack (>= 2.2.4)
|
||||
rack-session (>= 1.0.1)
|
||||
rack-test (>= 0.6.3)
|
||||
|
|
|
@ -1,9 +1,21 @@
|
|||
* Change `ActionDispatch::Testing::TestResponse#parsed_body` to parse HTML as
|
||||
a Nokogiri document
|
||||
|
||||
```ruby
|
||||
get "/posts"
|
||||
response.content_type # => "text/html; charset=utf-8"
|
||||
response.parsed_body.class # => Nokogiri::HTML5::Document
|
||||
response.parsed_body.to_html # => "<!DOCTYPE html>\n<html>\n..."
|
||||
```
|
||||
|
||||
*Sean Doyle*
|
||||
|
||||
* Add HTTP::Request#route_uri_pattern that returns URI pattern of matched route.
|
||||
|
||||
*Joel Hawksley*, *Kate Higa*
|
||||
|
||||
* Add `ActionDispatch::AssumeSSL` middleware that can be turned on via `config.assume_ssl`.
|
||||
It makes the application believe that all requests are arring over SSL. This is useful
|
||||
It makes the application believe that all requests are arriving over SSL. This is useful
|
||||
when proxying through a load balancer that terminates SSL, the forwarded request will appear
|
||||
as though its HTTP instead of HTTPS to the application. This makes redirects and cookie
|
||||
security target HTTP instead of HTTPS. This middleware makes the server assume that the
|
||||
|
|
|
@ -35,6 +35,7 @@ Gem::Specification.new do |s|
|
|||
|
||||
s.add_dependency "activesupport", version
|
||||
|
||||
s.add_dependency "nokogiri", ">= 1.8.5"
|
||||
s.add_dependency "rack", ">= 2.2.4"
|
||||
s.add_dependency "rack-session", ">= 1.0.1"
|
||||
s.add_dependency "rack-test", ">= 0.6.3"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "nokogiri"
|
||||
|
||||
module ActionDispatch
|
||||
class RequestEncoder # :nodoc:
|
||||
class IdentityEncoder
|
||||
|
@ -9,6 +11,9 @@ module ActionDispatch
|
|||
def response_parser; -> body { body }; end
|
||||
end
|
||||
|
||||
# :nodoc:
|
||||
HTMLResponseParser = defined?(::Nokogiri::HTML5) ? ::Nokogiri::HTML5 : ::Nokogiri::HTML
|
||||
|
||||
@encoders = { identity: IdentityEncoder.new }
|
||||
|
||||
attr_reader :response_parser
|
||||
|
@ -50,6 +55,7 @@ module ActionDispatch
|
|||
@encoders[mime_name] = new(mime_name, param_encoder, response_parser)
|
||||
end
|
||||
|
||||
register_encoder :html, response_parser: -> body { HTMLResponseParser.parse(body) }
|
||||
register_encoder :json, response_parser: -> body { JSON.parse(body) }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -19,19 +19,19 @@ module ActionDispatch
|
|||
#
|
||||
# ==== Examples
|
||||
# get "/posts"
|
||||
# response.content_type # => "text/html; charset=utf-8"
|
||||
# response.parsed_body.class # => String
|
||||
# response.parsed_body # => "<!DOCTYPE html>\n<html>\n..."
|
||||
# response.content_type # => "text/html; charset=utf-8"
|
||||
# response.parsed_body.class # => Nokogiri::HTML5::Document
|
||||
# response.parsed_body.to_html # => "<!DOCTYPE html>\n<html>\n..."
|
||||
#
|
||||
# get "/posts.json"
|
||||
# response.content_type # => "application/json; charset=utf-8"
|
||||
# response.parsed_body.class # => Array
|
||||
# response.parsed_body # => [{"id"=>42, "title"=>"Title"},...
|
||||
# response.content_type # => "application/json; charset=utf-8"
|
||||
# response.parsed_body.class # => Array
|
||||
# response.parsed_body # => [{"id"=>42, "title"=>"Title"},...
|
||||
#
|
||||
# get "/posts/42.json"
|
||||
# response.content_type # => "application/json; charset=utf-8"
|
||||
# response.parsed_body.class # => Hash
|
||||
# response.parsed_body # => {"id"=>42, "title"=>"Title"}
|
||||
# response.content_type # => "application/json; charset=utf-8"
|
||||
# response.parsed_body.class # => Hash
|
||||
# response.parsed_body # => {"id"=>42, "title"=>"Title"}
|
||||
def parsed_body
|
||||
@parsed_body ||= response_parser.call(body)
|
||||
end
|
||||
|
|
|
@ -26,5 +26,16 @@ class TestResponseTest < ActiveSupport::TestCase
|
|||
|
||||
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "application/json" }, '{ "foo": "fighters" }')
|
||||
assert_equal({ "foo" => "fighters" }, response.parsed_body)
|
||||
|
||||
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "text/html" }, <<~HTML)
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<div>Content</div>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
assert_kind_of(Nokogiri::XML::Document, response.parsed_body)
|
||||
assert_equal(response.parsed_body.at_xpath("/html/body/div").text, "Content")
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue