diff --git a/tests/test_request_params/test_body/test_nullable_and_defaults.py b/tests/test_request_params/test_body/test_nullable_and_defaults.py index e3d658ce7e..d0fe6fff96 100644 --- a/tests/test_request_params/test_body/test_nullable_and_defaults.py +++ b/tests/test_request_params/test_body/test_nullable_and_defaults.py @@ -5,6 +5,7 @@ import pytest from dirty_equals import IsList, IsOneOf, IsPartialDict from fastapi import Body, FastAPI from fastapi.testclient import TestClient +from inline_snapshot import Is, snapshot from pydantic import BaseModel, BeforeValidator, field_validator from .utils import get_body_model_name @@ -92,28 +93,30 @@ def test_nullable_required_schema(path: str): openapi = app.openapi() body_model_name = get_body_model_name(openapi, path) - assert app.openapi()["components"]["schemas"][body_model_name] == { - "properties": { - "int_val": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], + assert openapi["components"]["schemas"][body_model_name] == snapshot( + { + "properties": { + "int_val": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + }, + "str_val": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + }, + "list_val": { + "title": "List Val", + "anyOf": [ + {"type": "array", "items": {"type": "integer"}}, + {"type": "null"}, + ], + }, }, - "str_val": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - }, - "list_val": { - "title": "List Val", - "anyOf": [ - {"type": "array", "items": {"type": "integer"}}, - {"type": "null"}, - ], - }, - }, - "required": ["int_val", "str_val", "list_val"], - "title": body_model_name, - "type": "object", - } + "required": ["int_val", "str_val", "list_val"], + "title": Is(body_model_name), + "type": "object", + } + ) @pytest.mark.parametrize( @@ -165,28 +168,30 @@ def test_nullable_required_missing(path: str): client = TestClient(app) response = client.post(path, json={}) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "type": "missing", - "loc": ["body", "int_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - { - "type": "missing", - "loc": ["body", "str_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - { - "type": "missing", - "loc": ["body", "list_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "type": "missing", + "loc": ["body", "int_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + { + "type": "missing", + "loc": ["body", "str_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + { + "type": "missing", + "loc": ["body", "list_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + ] + } + ) @pytest.mark.parametrize( @@ -205,16 +210,18 @@ def test_nullable_required_no_body(path: str): client = TestClient(app) response = client.post(path) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "type": "missing", - "loc": ["body"], - "msg": "Field required", - "input": None, - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "type": "missing", + "loc": ["body"], + "msg": "Field required", + "input": None, + }, + ] + } + ) @pytest.mark.parametrize( @@ -229,16 +236,18 @@ def test_nullable_required_no_embed_missing(path: str): client = TestClient(app) response = client.post(path) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "input": None, - "loc": ["body"], - "msg": "Field required", - "type": "missing", - } - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "input": None, + "loc": ["body"], + "msg": "Field required", + "type": "missing", + } + ] + } + ) @pytest.mark.parametrize( @@ -267,16 +276,18 @@ def test_nullable_required_no_embed_pass_empty_dict( client = TestClient(app) response = client.post(path, json={}) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "input": {}, - "loc": ["body"], - "msg": msg, - "type": error_type, - } - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "input": {}, + "loc": ["body"], + "msg": Is(msg), + "type": Is(error_type), + } + ] + } + ) @pytest.mark.parametrize( @@ -487,30 +498,32 @@ def test_nullable_non_required_schema(path: str): openapi = app.openapi() body_model_name = get_body_model_name(openapi, path) - assert app.openapi()["components"]["schemas"][body_model_name] == { - "properties": { - "int_val": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema + assert openapi["components"]["schemas"][body_model_name] == snapshot( + { + "properties": { + "int_val": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "str_val": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "list_val": { + "title": "List Val", + "anyOf": [ + {"type": "array", "items": {"type": "integer"}}, + {"type": "null"}, + ], + # "default": None, # `None` values are omitted in OpenAPI schema + }, }, - "str_val": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema - }, - "list_val": { - "title": "List Val", - "anyOf": [ - {"type": "array", "items": {"type": "integer"}}, - {"type": "null"}, - ], - # "default": None, # `None` values are omitted in OpenAPI schema - }, - }, - "title": body_model_name, - "type": "object", - } + "title": Is(body_model_name), + "type": "object", + } + ) @pytest.mark.parametrize( @@ -595,16 +608,18 @@ def test_nullable_non_required_no_body(path: str): client = TestClient(app) response = client.post(path) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "type": "missing", - "loc": ["body"], - "msg": "Field required", - "input": None, - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "type": "missing", + "loc": ["body"], + "msg": "Field required", + "input": None, + }, + ] + } + ) @pytest.mark.parametrize( @@ -836,31 +851,33 @@ def test_nullable_with_non_null_default_schema(path: str): body_model_name = get_body_model_name(openapi, path) body_model = app.openapi()["components"]["schemas"][body_model_name] - assert body_model == { - "properties": { - "int_val": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], - "default": -1, - }, - "str_val": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - "default": "default", - }, - "list_val": IsPartialDict( - { - "title": "List Val", - "anyOf": [ - {"type": "array", "items": {"type": "integer"}}, - {"type": "null"}, - ], + assert body_model == snapshot( + { + "properties": { + "int_val": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + "default": -1, }, - ), - }, - "title": body_model_name, - "type": "object", - } + "str_val": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + "default": "default", + }, + "list_val": IsPartialDict( + { + "title": "List Val", + "anyOf": [ + {"type": "array", "items": {"type": "integer"}}, + {"type": "null"}, + ], + }, + ), + }, + "title": Is(body_model_name), + "type": "object", + } + ) if path == "/model-nullable-with-non-null-default": # Check default value for list_val param for model-based parameters only. @@ -949,16 +966,18 @@ def test_nullable_with_non_null_default_no_body(path: str): client = TestClient(app) response = client.post(path) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "type": "missing", - "loc": ["body"], - "msg": "Field required", - "input": None, - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "type": "missing", + "loc": ["body"], + "msg": "Field required", + "input": None, + }, + ] + } + ) @pytest.mark.parametrize( diff --git a/tests/test_request_params/test_cookie/test_nullable_and_defaults.py b/tests/test_request_params/test_cookie/test_nullable_and_defaults.py index f757997ddb..fdc9aeeaa9 100644 --- a/tests/test_request_params/test_cookie/test_nullable_and_defaults.py +++ b/tests/test_request_params/test_cookie/test_nullable_and_defaults.py @@ -5,6 +5,7 @@ import pytest from dirty_equals import IsList, IsOneOf from fastapi import Cookie, FastAPI from fastapi.testclient import TestClient +from inline_snapshot import snapshot from pydantic import BaseModel, BeforeValidator, field_validator app = FastAPI() @@ -67,26 +68,28 @@ async def read_model_nullable_required( ], ) def test_nullable_required_schema(path: str): - assert app.openapi()["paths"][path]["get"]["parameters"] == [ - { - "required": True, - "schema": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], + assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( + [ + { + "required": True, + "schema": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + }, + "name": "int_val", + "in": "cookie", }, - "name": "int_val", - "in": "cookie", - }, - { - "required": True, - "schema": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], + { + "required": True, + "schema": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + }, + "name": "str_val", + "in": "cookie", }, - "name": "str_val", - "in": "cookie", - }, - ] + ] + ) @pytest.mark.parametrize( @@ -105,22 +108,24 @@ def test_nullable_required_missing(path: str): "Validator should not be called if the value is missing" ) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "type": "missing", - "loc": ["cookie", "int_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - { - "type": "missing", - "loc": ["cookie", "str_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "type": "missing", + "loc": ["cookie", "int_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + { + "type": "missing", + "loc": ["cookie", "str_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + ] + } + ) @pytest.mark.parametrize( @@ -206,28 +211,30 @@ async def read_model_nullable_non_required( ], ) def test_nullable_non_required_schema(path: str): - assert app.openapi()["paths"][path]["get"]["parameters"] == [ - { - "required": False, - "schema": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema + assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( + [ + { + "required": False, + "schema": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "name": "int_val", + "in": "cookie", }, - "name": "int_val", - "in": "cookie", - }, - { - "required": False, - "schema": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema + { + "required": False, + "schema": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "name": "str_val", + "in": "cookie", }, - "name": "str_val", - "in": "cookie", - }, - ] + ] + ) @pytest.mark.parametrize( @@ -339,28 +346,30 @@ async def read_model_nullable_with_non_null_default( ], ) def test_nullable_with_non_null_default_schema(path: str): - assert app.openapi()["paths"][path]["get"]["parameters"] == [ - { - "required": False, - "schema": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], - "default": -1, + assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( + [ + { + "required": False, + "schema": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + "default": -1, + }, + "name": "int_val", + "in": "cookie", }, - "name": "int_val", - "in": "cookie", - }, - { - "required": False, - "schema": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - "default": "default", + { + "required": False, + "schema": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + "default": "default", + }, + "name": "str_val", + "in": "cookie", }, - "name": "str_val", - "in": "cookie", - }, - ] + ] + ) @pytest.mark.parametrize( diff --git a/tests/test_request_params/test_file/test_nullable_and_defaults.py b/tests/test_request_params/test_file/test_nullable_and_defaults.py index 80af58dedd..7fb3f0edc2 100644 --- a/tests/test_request_params/test_file/test_nullable_and_defaults.py +++ b/tests/test_request_params/test_file/test_nullable_and_defaults.py @@ -5,6 +5,7 @@ import pytest from dirty_equals import IsOneOf from fastapi import FastAPI, File, UploadFile from fastapi.testclient import TestClient +from inline_snapshot import Is, snapshot from pydantic import BeforeValidator from starlette.datastructures import UploadFile as StarletteUploadFile @@ -70,24 +71,29 @@ def test_nullable_required_schema(path: str): openapi = app.openapi() body_model_name = get_body_model_name(openapi, path) - assert app.openapi()["components"]["schemas"][body_model_name] == { - "properties": { - "file": { - "title": "File", - "anyOf": [{"type": "string", "format": "binary"}, {"type": "null"}], + assert openapi["components"]["schemas"][body_model_name] == snapshot( + { + "properties": { + "file": { + "title": "File", + "anyOf": [{"type": "string", "format": "binary"}, {"type": "null"}], + }, + "files": { + "title": "Files", + "anyOf": [ + { + "type": "array", + "items": {"type": "string", "format": "binary"}, + }, + {"type": "null"}, + ], + }, }, - "files": { - "title": "Files", - "anyOf": [ - {"type": "array", "items": {"type": "string", "format": "binary"}}, - {"type": "null"}, - ], - }, - }, - "required": ["file", "files"], - "title": body_model_name, - "type": "object", - } + "required": ["file", "files"], + "title": Is(body_model_name), + "type": "object", + } + ) @pytest.mark.parametrize( @@ -107,22 +113,24 @@ def test_nullable_required_missing(path: str): "Validator should not be called if the value is missing" ) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "type": "missing", - "loc": ["body", "file"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - { - "type": "missing", - "loc": ["body", "files"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "type": "missing", + "loc": ["body", "file"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + { + "type": "missing", + "loc": ["body", "files"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + ] + } + ) @pytest.mark.parametrize( @@ -242,25 +250,30 @@ def test_nullable_non_required_schema(path: str): openapi = app.openapi() body_model_name = get_body_model_name(openapi, path) - assert app.openapi()["components"]["schemas"][body_model_name] == { - "properties": { - "file": { - "title": "File", - "anyOf": [{"type": "string", "format": "binary"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema + assert openapi["components"]["schemas"][body_model_name] == snapshot( + { + "properties": { + "file": { + "title": "File", + "anyOf": [{"type": "string", "format": "binary"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "files": { + "title": "Files", + "anyOf": [ + { + "type": "array", + "items": {"type": "string", "format": "binary"}, + }, + {"type": "null"}, + ], + # "default": None, # `None` values are omitted in OpenAPI schema + }, }, - "files": { - "title": "Files", - "anyOf": [ - {"type": "array", "items": {"type": "string", "format": "binary"}}, - {"type": "null"}, - ], - # "default": None, # `None` values are omitted in OpenAPI schema - }, - }, - "title": body_model_name, - "type": "object", - } + "title": Is(body_model_name), + "type": "object", + } + ) @pytest.mark.parametrize( @@ -380,24 +393,32 @@ def test_nullable_with_non_null_default_schema(path: str): openapi = app.openapi() body_model_name = get_body_model_name(openapi, path) - assert app.openapi()["components"]["schemas"][body_model_name] == { - "properties": { - "file": { - "title": "File", - "anyOf": [{"type": "string", "format": "binary"}, {"type": "null"}], - "default": "default", # <= Default value for file looks strange to me + assert openapi["components"]["schemas"][body_model_name] == snapshot( + { + "properties": { + "file": { + "title": "File", + "anyOf": [ + {"type": "string", "format": "binary"}, + {"type": "null"}, + ], + "default": "default", # <= Default value here looks strange to me + }, + "files": { + "title": "Files", + "anyOf": [ + { + "type": "array", + "items": {"type": "string", "format": "binary"}, + }, + {"type": "null"}, + ], + }, }, - "files": { - "title": "Files", - "anyOf": [ - {"type": "array", "items": {"type": "string", "format": "binary"}}, - {"type": "null"}, - ], - }, - }, - "title": body_model_name, - "type": "object", - } + "title": Is(body_model_name), + "type": "object", + } + ) @pytest.mark.parametrize( diff --git a/tests/test_request_params/test_form/test_nullable_and_defaults.py b/tests/test_request_params/test_form/test_nullable_and_defaults.py index 0e1d82c1f3..58532e202c 100644 --- a/tests/test_request_params/test_form/test_nullable_and_defaults.py +++ b/tests/test_request_params/test_form/test_nullable_and_defaults.py @@ -5,6 +5,7 @@ import pytest from dirty_equals import IsList, IsOneOf, IsPartialDict from fastapi import FastAPI, Form from fastapi.testclient import TestClient +from inline_snapshot import Is, snapshot from pydantic import BaseModel, BeforeValidator, field_validator from .utils import get_body_model_name @@ -79,28 +80,30 @@ def test_nullable_required_schema(path: str): openapi = app.openapi() body_model_name = get_body_model_name(openapi, path) - assert app.openapi()["components"]["schemas"][body_model_name] == { - "properties": { - "int_val": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], + assert openapi["components"]["schemas"][body_model_name] == snapshot( + { + "properties": { + "int_val": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + }, + "str_val": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + }, + "list_val": { + "title": "List Val", + "anyOf": [ + {"type": "array", "items": {"type": "integer"}}, + {"type": "null"}, + ], + }, }, - "str_val": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - }, - "list_val": { - "title": "List Val", - "anyOf": [ - {"type": "array", "items": {"type": "integer"}}, - {"type": "null"}, - ], - }, - }, - "required": ["int_val", "str_val", "list_val"], - "title": body_model_name, - "type": "object", - } + "required": ["int_val", "str_val", "list_val"], + "title": Is(body_model_name), + "type": "object", + } + ) @pytest.mark.parametrize( @@ -120,28 +123,30 @@ def test_nullable_required_missing(path: str): "Validator should not be called if the value is missing" ) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "type": "missing", - "loc": ["body", "int_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - { - "type": "missing", - "loc": ["body", "str_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - { - "type": "missing", - "loc": ["body", "list_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "type": "missing", + "loc": ["body", "int_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + { + "type": "missing", + "loc": ["body", "str_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + { + "type": "missing", + "loc": ["body", "list_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + ] + } + ) @pytest.mark.parametrize( @@ -218,22 +223,24 @@ def test_nullable_required_pass_empty_str_to_int_val_and_list_val(path: str): call([""]), # list_val ] assert response.status_code == 422, response.text - assert response.json() == { - "detail": [ - { - "input": "", - "loc": ["body", "int_val"], - "msg": "Input should be a valid integer, unable to parse string as an integer", - "type": "int_parsing", - }, - { - "input": "", - "loc": ["body", "list_val", 0], - "msg": "Input should be a valid integer, unable to parse string as an integer", - "type": "int_parsing", - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "input": "", + "loc": ["body", "int_val"], + "msg": "Input should be a valid integer, unable to parse string as an integer", + "type": "int_parsing", + }, + { + "input": "", + "loc": ["body", "list_val", 0], + "msg": "Input should be a valid integer, unable to parse string as an integer", + "type": "int_parsing", + }, + ] + } + ) @pytest.mark.parametrize( @@ -326,30 +333,32 @@ def test_nullable_non_required_schema(path: str): openapi = app.openapi() body_model_name = get_body_model_name(openapi, path) - assert app.openapi()["components"]["schemas"][body_model_name] == { - "properties": { - "int_val": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema + assert openapi["components"]["schemas"][body_model_name] == snapshot( + { + "properties": { + "int_val": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "str_val": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "list_val": { + "title": "List Val", + "anyOf": [ + {"type": "array", "items": {"type": "integer"}}, + {"type": "null"}, + ], + # "default": None, # `None` values are omitted in OpenAPI schema + }, }, - "str_val": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema - }, - "list_val": { - "title": "List Val", - "anyOf": [ - {"type": "array", "items": {"type": "integer"}}, - {"type": "null"}, - ], - # "default": None, # `None` values are omitted in OpenAPI schema - }, - }, - "title": body_model_name, - "type": "object", - } + "title": Is(body_model_name), + "type": "object", + } + ) @pytest.mark.parametrize( @@ -445,16 +454,18 @@ def test_nullable_non_required_pass_empty_str_to_all(path: str): call([""]), # list_val ] assert response.status_code == 422, response.text - assert response.json() == { - "detail": [ - { - "input": "", - "loc": ["body", "list_val", 0], - "msg": "Input should be a valid integer, unable to parse string as an integer", - "type": "int_parsing", - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "input": "", + "loc": ["body", "list_val", 0], + "msg": "Input should be a valid integer, unable to parse string as an integer", + "type": "int_parsing", + }, + ] + } + ) @pytest.mark.parametrize( @@ -547,33 +558,35 @@ async def read_model_nullable_with_non_null_default( def test_nullable_with_non_null_default_schema(path: str): openapi = app.openapi() body_model_name = get_body_model_name(openapi, path) - body_model = app.openapi()["components"]["schemas"][body_model_name] + body_model = openapi["components"]["schemas"][body_model_name] - assert body_model == { - "properties": { - "int_val": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], - "default": -1, + assert body_model == snapshot( + { + "properties": { + "int_val": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + "default": -1, + }, + "str_val": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + "default": "default", + }, + "list_val": IsPartialDict( + { + "title": "List Val", + "anyOf": [ + {"type": "array", "items": {"type": "integer"}}, + {"type": "null"}, + ], + } + ), }, - "str_val": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - "default": "default", - }, - "list_val": IsPartialDict( - { - "title": "List Val", - "anyOf": [ - {"type": "array", "items": {"type": "integer"}}, - {"type": "null"}, - ], - } - ), - }, - "title": body_model_name, - "type": "object", - } + "title": Is(body_model_name), + "type": "object", + } + ) if path == "/model-nullable-with-non-null-default": # Check default value for list_val param for model-based parameters only. @@ -691,16 +704,18 @@ def test_nullable_with_non_null_default_pass_empty_str_to_all(path: str): call([""]), # list_val ] assert response.status_code == 422, response.text # pragma: no cover - assert response.json() == { # pragma: no cover - "detail": [ - { - "input": "", - "loc": ["body", "list_val", 0], - "msg": "Input should be a valid integer, unable to parse string as an integer", - "type": "int_parsing", - }, - ] - } + assert response.json() == snapshot( # pragma: no cover + { + "detail": [ + { + "input": "", + "loc": ["body", "list_val", 0], + "msg": "Input should be a valid integer, unable to parse string as an integer", + "type": "int_parsing", + }, + ] + } + ) # TODO: Remove 'no cover' when the issue is fixed diff --git a/tests/test_request_params/test_header/test_nullable_and_defaults.py b/tests/test_request_params/test_header/test_nullable_and_defaults.py index 474fb0ef47..4680973fe5 100644 --- a/tests/test_request_params/test_header/test_nullable_and_defaults.py +++ b/tests/test_request_params/test_header/test_nullable_and_defaults.py @@ -5,6 +5,7 @@ import pytest from dirty_equals import AnyThing, IsList, IsOneOf, IsPartialDict from fastapi import FastAPI, Header from fastapi.testclient import TestClient +from inline_snapshot import snapshot from pydantic import BaseModel, BeforeValidator, field_validator app = FastAPI() @@ -80,38 +81,40 @@ async def read_model_nullable_required( ], ) def test_nullable_required_schema(path: str): - assert app.openapi()["paths"][path]["get"]["parameters"] == [ - { - "required": True, - "schema": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], + assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( + [ + { + "required": True, + "schema": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + }, + "name": "int-val", + "in": "header", }, - "name": "int-val", - "in": "header", - }, - { - "required": True, - "schema": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], + { + "required": True, + "schema": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + }, + "name": "str-val", + "in": "header", }, - "name": "str-val", - "in": "header", - }, - { - "required": True, - "schema": { - "title": "List Val", - "anyOf": [ - {"type": "array", "items": {"type": "integer"}}, - {"type": "null"}, - ], + { + "required": True, + "schema": { + "title": "List Val", + "anyOf": [ + {"type": "array", "items": {"type": "integer"}}, + {"type": "null"}, + ], + }, + "name": "list-val", + "in": "header", }, - "name": "list-val", - "in": "header", - }, - ] + ] + ) @pytest.mark.parametrize( @@ -138,28 +141,30 @@ def test_nullable_required_missing(path: str): "Validator should not be called if the value is missing" ) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "type": "missing", - "loc": ["header", "int-val"], - "msg": "Field required", - "input": AnyThing(), - }, - { - "type": "missing", - "loc": ["header", "str-val"], - "msg": "Field required", - "input": AnyThing(), - }, - { - "type": "missing", - "loc": ["header", "list-val"], - "msg": "Field required", - "input": AnyThing(), - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "type": "missing", + "loc": ["header", "int-val"], + "msg": "Field required", + "input": AnyThing(), + }, + { + "type": "missing", + "loc": ["header", "str-val"], + "msg": "Field required", + "input": AnyThing(), + }, + { + "type": "missing", + "loc": ["header", "list-val"], + "msg": "Field required", + "input": AnyThing(), + }, + ] + } + ) @pytest.mark.parametrize( @@ -293,41 +298,43 @@ async def read_model_nullable_non_required( ], ) def test_nullable_non_required_schema(path: str): - assert app.openapi()["paths"][path]["get"]["parameters"] == [ - { - "required": False, - "schema": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema + assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( + [ + { + "required": False, + "schema": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "name": "int-val", + "in": "header", }, - "name": "int-val", - "in": "header", - }, - { - "required": False, - "schema": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema + { + "required": False, + "schema": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "name": "str-val", + "in": "header", }, - "name": "str-val", - "in": "header", - }, - { - "required": False, - "schema": { - "title": "List Val", - "anyOf": [ - {"type": "array", "items": {"type": "integer"}}, - {"type": "null"}, - ], - # "default": None, # `None` values are omitted in OpenAPI schema + { + "required": False, + "schema": { + "title": "List Val", + "anyOf": [ + {"type": "array", "items": {"type": "integer"}}, + {"type": "null"}, + ], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "name": "list-val", + "in": "header", }, - "name": "list-val", - "in": "header", - }, - ] + ] + ) @pytest.mark.parametrize( @@ -488,42 +495,44 @@ async def read_model_nullable_with_non_null_default( ) def test_nullable_with_non_null_default_schema(path: str): parameters = app.openapi()["paths"][path]["get"]["parameters"] - assert parameters == [ - { - "required": False, - "schema": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], - "default": -1, + assert parameters == snapshot( + [ + { + "required": False, + "schema": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + "default": -1, + }, + "name": "int-val", + "in": "header", }, - "name": "int-val", - "in": "header", - }, - { - "required": False, - "schema": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - "default": "default", + { + "required": False, + "schema": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + "default": "default", + }, + "name": "str-val", + "in": "header", }, - "name": "str-val", - "in": "header", - }, - { - "required": False, - "schema": IsPartialDict( - { - "title": "List Val", - "anyOf": [ - {"type": "array", "items": {"type": "integer"}}, - {"type": "null"}, - ], - } - ), - "name": "list-val", - "in": "header", - }, - ] + { + "required": False, + "schema": IsPartialDict( + { + "title": "List Val", + "anyOf": [ + {"type": "array", "items": {"type": "integer"}}, + {"type": "null"}, + ], + } + ), + "name": "list-val", + "in": "header", + }, + ] + ) if path == "/model-nullable-with-non-null-default": # Check default value for list_val param for model-based parameters only. diff --git a/tests/test_request_params/test_query/test_nullable_and_defaults.py b/tests/test_request_params/test_query/test_nullable_and_defaults.py index 648f265802..f018d7e0a3 100644 --- a/tests/test_request_params/test_query/test_nullable_and_defaults.py +++ b/tests/test_request_params/test_query/test_nullable_and_defaults.py @@ -5,6 +5,7 @@ import pytest from dirty_equals import IsList, IsOneOf, IsPartialDict from fastapi import FastAPI, Query from fastapi.testclient import TestClient +from inline_snapshot import snapshot from pydantic import BaseModel, BeforeValidator, field_validator app = FastAPI() @@ -73,38 +74,40 @@ async def read_model_nullable_required( ], ) def test_nullable_required_schema(path: str): - assert app.openapi()["paths"][path]["get"]["parameters"] == [ - { - "required": True, - "schema": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], + assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( + [ + { + "required": True, + "schema": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + }, + "name": "int_val", + "in": "query", }, - "name": "int_val", - "in": "query", - }, - { - "required": True, - "schema": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], + { + "required": True, + "schema": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + }, + "name": "str_val", + "in": "query", }, - "name": "str_val", - "in": "query", - }, - { - "in": "query", - "name": "list_val", - "required": True, - "schema": { - "anyOf": [ - {"items": {"type": "integer"}, "type": "array"}, - {"type": "null"}, - ], - "title": "List Val", + { + "in": "query", + "name": "list_val", + "required": True, + "schema": { + "anyOf": [ + {"items": {"type": "integer"}, "type": "array"}, + {"type": "null"}, + ], + "title": "List Val", + }, }, - }, - ] + ] + ) @pytest.mark.parametrize( @@ -124,28 +127,30 @@ def test_nullable_required_missing(path: str): "Validator should not be called if the value is missing" ) assert response.status_code == 422 - assert response.json() == { - "detail": [ - { - "type": "missing", - "loc": ["query", "int_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - { - "type": "missing", - "loc": ["query", "str_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - { - "type": "missing", - "loc": ["query", "list_val"], - "msg": "Field required", - "input": IsOneOf(None, {}), - }, - ] - } + assert response.json() == snapshot( + { + "detail": [ + { + "type": "missing", + "loc": ["query", "int_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + { + "type": "missing", + "loc": ["query", "str_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + { + "type": "missing", + "loc": ["query", "list_val"], + "msg": "Field required", + "input": IsOneOf(None, {}), + }, + ] + } + ) @pytest.mark.parametrize( @@ -239,41 +244,43 @@ async def read_model_nullable_non_required( ], ) def test_nullable_non_required_schema(path: str): - assert app.openapi()["paths"][path]["get"]["parameters"] == [ - { - "required": False, - "schema": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema + assert app.openapi()["paths"][path]["get"]["parameters"] == snapshot( + [ + { + "required": False, + "schema": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "name": "int_val", + "in": "query", }, - "name": "int_val", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - # "default": None, # `None` values are omitted in OpenAPI schema + { + "required": False, + "schema": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + # "default": None, # `None` values are omitted in OpenAPI schema + }, + "name": "str_val", + "in": "query", }, - "name": "str_val", - "in": "query", - }, - { - "in": "query", - "name": "list_val", - "required": False, - "schema": { - "anyOf": [ - {"items": {"type": "integer"}, "type": "array"}, - {"type": "null"}, - ], - "title": "List Val", - # "default": None, # `None` values are omitted in OpenAPI schema + { + "in": "query", + "name": "list_val", + "required": False, + "schema": { + "anyOf": [ + {"items": {"type": "integer"}, "type": "array"}, + {"type": "null"}, + ], + "title": "List Val", + # "default": None, # `None` values are omitted in OpenAPI schema + }, }, - }, - ] + ] + ) @pytest.mark.parametrize( @@ -394,42 +401,44 @@ async def read_model_nullable_with_non_null_default( ) def test_nullable_with_non_null_default_schema(path: str): parameters = app.openapi()["paths"][path]["get"]["parameters"] - assert parameters == [ - { - "required": False, - "schema": { - "title": "Int Val", - "anyOf": [{"type": "integer"}, {"type": "null"}], - "default": -1, + assert parameters == snapshot( + [ + { + "required": False, + "schema": { + "title": "Int Val", + "anyOf": [{"type": "integer"}, {"type": "null"}], + "default": -1, + }, + "name": "int_val", + "in": "query", }, - "name": "int_val", - "in": "query", - }, - { - "required": False, - "schema": { - "title": "Str Val", - "anyOf": [{"type": "string"}, {"type": "null"}], - "default": "default", + { + "required": False, + "schema": { + "title": "Str Val", + "anyOf": [{"type": "string"}, {"type": "null"}], + "default": "default", + }, + "name": "str_val", + "in": "query", }, - "name": "str_val", - "in": "query", - }, - { - "in": "query", - "name": "list_val", - "required": False, - "schema": IsPartialDict( - { - "anyOf": [ - {"items": {"type": "integer"}, "type": "array"}, - {"type": "null"}, - ], - "title": "List Val", - } - ), - }, - ] + { + "in": "query", + "name": "list_val", + "required": False, + "schema": IsPartialDict( + { + "anyOf": [ + {"items": {"type": "integer"}, "type": "array"}, + {"type": "null"}, + ], + "title": "List Val", + } + ), + }, + ] + ) if path == "/model-nullable-with-non-null-default": # Check default value for list_val param for model-based parameters only.