diff --git a/tests/test_forms_single_model.py b/tests/test_forms_single_model.py index 880ab3820..01c7dc0d5 100644 --- a/tests/test_forms_single_model.py +++ b/tests/test_forms_single_model.py @@ -1,7 +1,7 @@ from typing import List, Optional from dirty_equals import IsDict -from fastapi import FastAPI, Form +from fastapi import FastAPI, File, Form from fastapi.testclient import TestClient from pydantic import BaseModel, Field from typing_extensions import Annotated @@ -17,11 +17,24 @@ class FormModel(BaseModel): alias_with: str = Field(alias="with", default="nothing") +class FormWithFileModel(BaseModel): + comment: str + file_data: bytes = File() + + @app.post("/form/") def post_form(user: Annotated[FormModel, Form()]): return user +@app.post("/form-with-file/") +def post_form_(form_data: Annotated[FormWithFileModel, Form()]): + return { + "comment": form_data.comment, + "file_size": len(form_data.file_data), + } + + client = TestClient(app) @@ -131,3 +144,74 @@ def test_no_data(): ] } ) + + +def test_form_with_file(): + file_content = b"Hello, this is a test file." + response = client.post( + "/form-with-file/", + data={"comment": "This is a comment."}, + files={"file_data": ("test.txt", file_content, "text/plain")}, + ) + assert response.status_code == 200, response.text + assert response.json() == { + "comment": "This is a comment.", + "file_size": len(file_content), + } + + +def test_form_with_file_missing_file(): + response = client.post( + "/form-with-file/", + data={"comment": "This is a comment."}, + ) + assert response.status_code == 422, response.text + assert response.json() == IsDict( + { + "detail": [ + { + "type": "missing", + "loc": ["body", "file_data"], + "msg": "Field required", + "input": {"comment": "This is a comment."}, + } + ] + } + ) | IsDict( + # TODO: remove when deprecating Pydantic v1 + { + "detail": [ + { + "loc": ["body", "file_data"], + "msg": "field required", + "type": "value_error.missing", + } + ] + } + ) + + +def test_form_with_file_openapi(): + response = client.get("/openapi.json") + assert response.status_code == 200, response.text + openapi_schema = response.json() + assert openapi_schema["paths"]["/form-with-file/"]["post"]["requestBody"] == { + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/FormWithFileModel", + }, + }, + }, + "required": True, + } + + assert openapi_schema["components"]["schemas"]["FormWithFileModel"] == { + "title": "FormWithFileModel", + "type": "object", + "properties": { + "file_data": {"title": "File Data", "type": "string", "format": "binary"}, + "comment": {"title": "Comment", "type": "string"}, + }, + "required": ["comment", "file_data"], + }