/ fastapi-template-users / tests / utils / test_docs.py
test_docs.py
  1  from unittest.mock import MagicMock
  2  
  3  from fastapi import FastAPI
  4  from pydantic import BaseModel, Field
  5  from pytest_mock import MockerFixture
  6  
  7  from .._utils import mock_dict
  8  from api.utils import docs
  9  
 10  
 11  async def test__responses() -> None:
 12      default = MagicMock()
 13  
 14      def make_exception(status_code: int) -> MagicMock:
 15          out = MagicMock()
 16          out.__name__ = MagicMock()
 17          out.status_code = status_code
 18          return out
 19  
 20      args = [a := make_exception(401), b := make_exception(403), c := make_exception(403), d := make_exception(404)]
 21  
 22      result = docs.responses(default, *args)
 23  
 24      assert result == {
 25          200: {"model": default},
 26          401: {
 27              "description": b"Unauthorized",
 28              "content": {
 29                  "application/json": {
 30                      "examples": {a.__name__: {"description": a.description, "value": {"detail": a.detail}}}
 31                  }
 32              },
 33          },
 34          403: {
 35              "description": b"Forbidden",
 36              "content": {
 37                  "application/json": {
 38                      "examples": {
 39                          f"{b.__name__} (1/2)": {"description": b.description, "value": {"detail": b.detail}},
 40                          f"{c.__name__} (2/2)": {"description": c.description, "value": {"detail": c.detail}},
 41                      }
 42                  }
 43              },
 44          },
 45          404: {
 46              "description": b"Not Found",
 47              "content": {
 48                  "application/json": {
 49                      "examples": {d.__name__: {"description": d.description, "value": {"detail": d.detail}}}
 50                  }
 51              },
 52          },
 53      }
 54  
 55  
 56  async def test__get_example() -> None:
 57      arg = MagicMock()
 58      arg.Config.schema_extra = {"example": (expected := MagicMock())}
 59  
 60      assert docs.get_example(arg) == expected
 61  
 62  
 63  async def test__example(mocker: MockerFixture) -> None:
 64      get_example_patch = mocker.patch("api.utils.docs.get_example")
 65  
 66      args = [a := MagicMock(), b := MagicMock()]
 67      get_example_patch.side_effect = lambda x: MagicMock(
 68          items=lambda: [(x.first.key, x.first.value), (x.second.key, x.second.value)]
 69      )
 70      kwargs = mock_dict(5, True)
 71  
 72      result = docs.example(*args, **kwargs)
 73  
 74      assert result.schema_extra == {
 75          "example": {
 76              a.first.key: a.first.value,
 77              a.second.key: a.second.value,
 78              b.first.key: b.first.value,
 79              b.second.key: b.second.value,
 80              **kwargs,
 81          }
 82      }
 83  
 84  
 85  async def test__add_endpoint_links_to_openapi_docs() -> None:
 86      app = FastAPI(
 87          description="`GET /test` test `POST /foobar`",
 88          openapi_tags=[{"name": "test", "description": "asdf `GET /test`"}],
 89      )
 90  
 91      class Model(BaseModel):
 92          test: str = Field(description="xyz `POST /foobar`")
 93  
 94      @app.get("/test", tags=["test"], responses=docs.responses(Model))
 95      async def test() -> None:
 96          """Test endpoint. `POST /foobar`"""
 97          pass
 98  
 99      @app.post("/foobar", tags=["test"])
100      async def foobar() -> None:
101          """Foobar endpoint. `GET /test`"""
102          pass
103  
104      docs.add_endpoint_links_to_openapi_docs(app.openapi())
105      schema = app.openapi()
106      assert (
107          schema["info"]["description"]
108          == "[`GET /test`](docs#/test/test_test_get) test [`POST /foobar`](docs#/test/foobar_foobar_post)"
109      )
110      assert schema["tags"][0]["description"] == "asdf [`GET /test`](docs#/test/test_test_get)"
111      assert (
112          schema["paths"]["/test"]["get"]["description"]
113          == "Test endpoint. [`POST /foobar`](docs#/test/foobar_foobar_post)"
114      )
115      assert (
116          schema["paths"]["/foobar"]["post"]["description"] == "Foobar endpoint. [`GET /test`](docs#/test/test_test_get)"
117      )
118      assert (
119          schema["components"]["schemas"]["Model"]["properties"]["test"]["description"]
120          == "xyz [`POST /foobar`](docs#/test/foobar_foobar_post)"
121      )