Skip to content

Commit a7a1217

Browse files
authored
Merge pull request rails#49003 from seanpdoyle/test-response-parsed-body-pattern-matching
Ensure `response.parsed_body` support for pattern matching
2 parents a5f64bf + 0f4ab82 commit a7a1217

File tree

6 files changed

+84
-8
lines changed

6 files changed

+84
-8
lines changed

actionpack/CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
* Parse JSON `response.parsed_body` with `ActiveSupport::HashWithIndifferentAccess`
2+
3+
Integrate with Minitest's new `assert_pattern` by parsing the JSON contents
4+
of `response.parsed_body` with `ActiveSupport::HashWithIndifferentAccess`, so
5+
that it's pattern-matching compatible.
6+
7+
*Sean Doyle*
8+
19
* Add support for Playwright as a driver for system tests.
210

311
*Yuki Nishijima*

actionpack/lib/action_dispatch/testing/request_encoder.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@ def self.register_encoder(mime_name, param_encoder: nil, response_parser: nil)
5353
end
5454

5555
register_encoder :html, response_parser: -> body { Rails::Dom::Testing.html_document.parse(body) }
56-
register_encoder :json, response_parser: -> body { JSON.parse(body) }
56+
register_encoder :json, response_parser: -> body { JSON.parse(body, object_class: ActiveSupport::HashWithIndifferentAccess) }
5757
end
5858
end

actionpack/lib/action_dispatch/testing/test_response.rb

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,29 @@ def self.from_response(response)
2323
# response.parsed_body.class # => Nokogiri::HTML5::Document
2424
# response.parsed_body.to_html # => "<!DOCTYPE html>\n<html>\n..."
2525
#
26+
# assert_pattern { response.parsed_body.at("main") => { content: "Hello, world" } }
27+
#
28+
# response.parsed_body.at("main") => {name:, content:}
29+
# assert_equal "main", name
30+
# assert_equal "Some main content", content
31+
#
2632
# get "/posts.json"
2733
# response.content_type # => "application/json; charset=utf-8"
2834
# response.parsed_body.class # => Array
2935
# response.parsed_body # => [{"id"=>42, "title"=>"Title"},...
3036
#
37+
# assert_pattern { response.parsed_body => [{ id: 42 }] }
38+
#
3139
# get "/posts/42.json"
3240
# response.content_type # => "application/json; charset=utf-8"
33-
# response.parsed_body.class # => Hash
41+
# response.parsed_body.class # => ActiveSupport::HashWithIndifferentAccess
3442
# response.parsed_body # => {"id"=>42, "title"=>"Title"}
43+
#
44+
# assert_pattern { response.parsed_body => [{ title: /title/i }] }
45+
#
46+
# response.parsed_body => {id:, title:}
47+
# assert_equal 42, id
48+
# assert_equal "Title", title
3549
def parsed_body
3650
@parsed_body ||= response_parser.call(body)
3751
end

actionpack/test/dispatch/test_response_test.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ def assert_response_code_range(range, predicate)
2525
assert_equal response.body, response.parsed_body
2626

2727
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "application/json" }, '{ "foo": "fighters" }')
28+
assert_kind_of ActiveSupport::HashWithIndifferentAccess, response.parsed_body
2829
assert_equal({ "foo" => "fighters" }, response.parsed_body)
2930

3031
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "text/html" }, <<~HTML)
@@ -38,4 +39,10 @@ def assert_response_code_range(range, predicate)
3839
assert_kind_of(Nokogiri::XML::Document, response.parsed_body)
3940
assert_equal(response.parsed_body.at_xpath("/html/body/div").text, "Content")
4041
end
42+
43+
if RUBY_VERSION >= "3.1"
44+
require_relative "./test_response_test/pattern_matching_test_cases"
45+
46+
include PatternMatchingTestCases
47+
end
4148
end
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# frozen_string_literal: true
2+
3+
module TestResponseTest::PatternMatchingTestCases
4+
extend ActiveSupport::Concern
5+
6+
included do
7+
test "JSON response Hash pattern matching" do
8+
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "application/json" }, '{ "foo": "fighters" }')
9+
10+
# rubocop:disable Lint/Syntax
11+
assert_pattern { response.parsed_body => { foo: /fighter/ } }
12+
# rubocop:enable Lint/Syntax
13+
end
14+
15+
test "JSON response Array pattern matching" do
16+
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "application/json" }, '[{ "foo": "fighters" }, { "nir": "vana" }]')
17+
# rubocop:disable Lint/Syntax
18+
assert_pattern { response.parsed_body => [{ foo: /fighter/ }, { nir: /vana/ }] }
19+
# rubocop:enable Lint/Syntax
20+
end
21+
22+
test "HTML response pattern matching" do
23+
response = ActionDispatch::TestResponse.create(200, { "Content-Type" => "text/html" }, <<~HTML)
24+
<html>
25+
<head></head>
26+
<body>
27+
<main><h1>Some main content</h1></main>
28+
</body>
29+
</html>
30+
HTML
31+
html = response.parsed_body
32+
33+
# rubocop:disable Lint/Syntax
34+
html.at("main") => {name:, content:}
35+
# rubocop:enable Lint/Syntax
36+
37+
assert_equal "main", name
38+
assert_equal "Some main content", content
39+
40+
# rubocop:disable Lint/Syntax
41+
assert_pattern { html.at("main") => { content: "Some main content" } }
42+
assert_pattern { html.at("main") => { content: /content/ } }
43+
assert_pattern { html.at("main") => { children: [{ name: "h1", content: /content/ }] } }
44+
# rubocop:enable Lint/Syntax
45+
end
46+
end
47+
end

activestorage/test/controllers/direct_uploads_controller_test.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,11 @@ class ActiveStorage::DiskDirectUploadsControllerTest < ActionDispatch::Integrati
138138
test "creating new direct upload" do
139139
checksum = OpenSSL::Digest::MD5.base64digest("Hello")
140140
metadata = {
141-
"foo": "bar",
142-
"my_key_1": "my_value_1",
143-
"my_key_2": "my_value_2",
144-
"platform": "my_platform",
145-
"library_ID": "12345"
141+
"foo" => "bar",
142+
"my_key_1" => "my_value_1",
143+
"my_key_2" => "my_value_2",
144+
"platform" => "my_platform",
145+
"library_ID" => "12345"
146146
}
147147

148148
post rails_direct_uploads_url, params: { blob: {
@@ -153,7 +153,7 @@ class ActiveStorage::DiskDirectUploadsControllerTest < ActionDispatch::Integrati
153153
assert_equal "hello.txt", details["filename"]
154154
assert_equal 6, details["byte_size"]
155155
assert_equal checksum, details["checksum"]
156-
assert_equal metadata, details["metadata"].deep_transform_keys(&:to_sym)
156+
assert_equal metadata, details["metadata"]
157157
assert_equal "text/plain", details["content_type"]
158158
assert_match(/rails\/active_storage\/disk/, details["direct_upload"]["url"])
159159
assert_equal({ "Content-Type" => "text/plain" }, details["direct_upload"]["headers"])

0 commit comments

Comments
 (0)