diff --git a/lib/open_api_spex/cast/utils.ex b/lib/open_api_spex/cast/utils.ex index 5be0b02a..c2ba810b 100644 --- a/lib/open_api_spex/cast/utils.ex +++ b/lib/open_api_spex/cast/utils.ex @@ -73,9 +73,19 @@ defmodule OpenApiSpex.Cast.Utils do - If multiple `content-type` headers are found, the function will only return the value of the first one. """ - @spec content_type_from_header(Plug.Conn.t()) :: String.t() | nil - def content_type_from_header(conn = %Plug.Conn{}) do - case Plug.Conn.get_req_header(conn, "content-type") do + @spec content_type_from_header(Plug.Conn.t(), :request | :response) :: + String.t() | nil + def content_type_from_header(conn = %Plug.Conn{}, header_location \\ :request) do + content_type = + case header_location do + :request -> + Plug.Conn.get_req_header(conn, "content-type") + + :response -> + Plug.Conn.get_resp_header(conn, "content-type") + end + + case content_type do [header_value | _] -> header_value |> String.split(";") diff --git a/lib/open_api_spex/test/test_assertions.ex b/lib/open_api_spex/test/test_assertions.ex index 42f95b2e..6d089024 100644 --- a/lib/open_api_spex/test/test_assertions.ex +++ b/lib/open_api_spex/test/test_assertions.ex @@ -136,7 +136,7 @@ defmodule OpenApiSpex.TestAssertions do case operation_lookup[operation_id] do nil -> flunk( - "Failed to resolve schema. Unable to find a response for operation_id: #{operation_id} for response status code: #{conn.status}" + "Failed to resolve a response schema for operation_id: #{operation_id} for status code: #{conn.status}" ) operation -> @@ -154,20 +154,19 @@ defmodule OpenApiSpex.TestAssertions do ) :: term | no_return defp validate_operation_response(conn, %Operation{operationId: operation_id} = operation, spec) do - content_type = Utils.content_type_from_header(conn) + content_type = Utils.content_type_from_header(conn, :response) resolved_schema = - get_in(operation, [ - Access.key!(:responses), - Access.key!(conn.status), - Access.key!(:content), - content_type, - Access.key!(:schema) - ]) + operation + |> Map.get(:responses, %{}) + |> Map.get(conn.status, %{}) + |> Map.get(:content, %{}) + |> Map.get(content_type, %{}) + |> Map.get(:schema) if is_nil(resolved_schema) do flunk( - "Failed to resolve schema! Unable to find a response for operation_id: #{operation_id} for response status code: #{conn.status} and content type #{content_type}" + "Failed to resolve a response schema for operation_id: #{operation_id} for status code: #{conn.status} and content type: #{content_type}" ) end diff --git a/test/test_assertions_test.exs b/test/test_assertions_test.exs index 0959eef5..9174b5e2 100644 --- a/test/test_assertions_test.exs +++ b/test/test_assertions_test.exs @@ -129,14 +129,11 @@ defmodule OpenApiSpex.TestAssertionsTest do conn = OpenApiSpexTest.Router.call(conn, []) assert conn.status == 200 - try do - TestAssertions.assert_operation_response(conn, "not_a_real_operation_id") - raise RuntimeError, "Should flunk" - rescue - e in ExUnit.AssertionError -> - assert e.message =~ - "Failed to resolve schema. Unable to find a response for operation_id: not_a_real_operation_id for response status code: 200" - end + assert_raise( + ExUnit.AssertionError, + ~r/Failed to resolve a response schema for operation_id: not_a_real_operation_id for status code: 200/, + fn -> TestAssertions.assert_operation_response(conn, "not_a_real_operation_id") end + ) end test "invalid schema" do @@ -149,14 +146,29 @@ defmodule OpenApiSpex.TestAssertionsTest do assert conn.status == 200 - try do - TestAssertions.assert_operation_response(conn, "showPetById") - raise RuntimeError, "Should flunk" - rescue - e in ExUnit.AssertionError -> - assert e.message =~ - "Value does not conform to schema PetResponse: Failed to cast value to one of: no schemas validate at" - end + assert_raise( + ExUnit.AssertionError, + ~r/Value does not conform to schema PetResponse: Failed to cast value to one of: no schemas validate at/, + fn -> TestAssertions.assert_operation_response(conn, "showPetById") end + ) + end + + test "returns an error when the response content-type does not match the schema" do + conn = + :get + |> Plug.Test.conn("/api/pets") + |> Plug.Conn.put_req_header("content-type", "application/json") + |> Plug.Conn.put_resp_header("content-type", "unexpected-content-type") + + conn = OpenApiSpexTest.Router.call(conn, []) + + assert conn.status == 200 + + assert_raise( + ExUnit.AssertionError, + ~r/Failed to resolve a response schema for operation_id: showPetById for status code: 200 and content type: unexpected-content-type/, + fn -> TestAssertions.assert_operation_response(conn, "showPetById") end + ) end end end