Coverage for tests/test_tutorial/test_query_param_models/test_tutorial002.py: 100%
31 statements
« prev ^ index » next coverage.py v7.6.1, created at 2025-01-13 13:38 +0000
« prev ^ index » next coverage.py v7.6.1, created at 2025-01-13 13:38 +0000
1import importlib 1abcde
3import pytest 1abcde
4from dirty_equals import IsDict 1abcde
5from fastapi.testclient import TestClient 1abcde
6from inline_snapshot import snapshot 1abcde
8from tests.utils import needs_py39, needs_py310, needs_pydanticv1, needs_pydanticv2 1abcde
11@pytest.fixture( 1abcde
12 name="client",
13 params=[
14 pytest.param("tutorial002", marks=needs_pydanticv2),
15 pytest.param("tutorial002_py39", marks=[needs_py39, needs_pydanticv2]),
16 pytest.param("tutorial002_py310", marks=[needs_py310, needs_pydanticv2]),
17 pytest.param("tutorial002_an", marks=needs_pydanticv2),
18 pytest.param("tutorial002_an_py39", marks=[needs_py39, needs_pydanticv2]),
19 pytest.param("tutorial002_an_py310", marks=[needs_py310, needs_pydanticv2]),
20 pytest.param("tutorial002_pv1", marks=[needs_pydanticv1, needs_pydanticv1]),
21 pytest.param("tutorial002_pv1_py39", marks=[needs_py39, needs_pydanticv1]),
22 pytest.param("tutorial002_pv1_py310", marks=[needs_py310, needs_pydanticv1]),
23 pytest.param("tutorial002_pv1_an", marks=[needs_pydanticv1]),
24 pytest.param("tutorial002_pv1_an_py39", marks=[needs_py39, needs_pydanticv1]),
25 pytest.param("tutorial002_pv1_an_py310", marks=[needs_py310, needs_pydanticv1]),
26 ],
27)
28def get_client(request: pytest.FixtureRequest): 1abcde
29 mod = importlib.import_module(f"docs_src.query_param_models.{request.param}") 1abcde
31 client = TestClient(mod.app) 1abcde
32 return client 1abcde
35def test_query_param_model(client: TestClient): 1abcde
36 response = client.get( 1fghij
37 "/items/",
38 params={
39 "limit": 10,
40 "offset": 5,
41 "order_by": "updated_at",
42 "tags": ["tag1", "tag2"],
43 },
44 )
45 assert response.status_code == 200 1fghij
46 assert response.json() == { 1fghij
47 "limit": 10,
48 "offset": 5,
49 "order_by": "updated_at",
50 "tags": ["tag1", "tag2"],
51 }
54def test_query_param_model_defaults(client: TestClient): 1abcde
55 response = client.get("/items/") 1klmno
56 assert response.status_code == 200 1klmno
57 assert response.json() == { 1klmno
58 "limit": 100,
59 "offset": 0,
60 "order_by": "created_at",
61 "tags": [],
62 }
65def test_query_param_model_invalid(client: TestClient): 1abcde
66 response = client.get( 1pqrst
67 "/items/",
68 params={
69 "limit": 150,
70 "offset": -1,
71 "order_by": "invalid",
72 },
73 )
74 assert response.status_code == 422 1pqrst
75 assert response.json() == snapshot( 1pqrst
76 IsDict(
77 {
78 "detail": [
79 {
80 "type": "less_than_equal",
81 "loc": ["query", "limit"],
82 "msg": "Input should be less than or equal to 100",
83 "input": "150",
84 "ctx": {"le": 100},
85 },
86 {
87 "type": "greater_than_equal",
88 "loc": ["query", "offset"],
89 "msg": "Input should be greater than or equal to 0",
90 "input": "-1",
91 "ctx": {"ge": 0},
92 },
93 {
94 "type": "literal_error",
95 "loc": ["query", "order_by"],
96 "msg": "Input should be 'created_at' or 'updated_at'",
97 "input": "invalid",
98 "ctx": {"expected": "'created_at' or 'updated_at'"},
99 },
100 ]
101 }
102 )
103 | IsDict(
104 # TODO: remove when deprecating Pydantic v1
105 {
106 "detail": [
107 {
108 "type": "value_error.number.not_le",
109 "loc": ["query", "limit"],
110 "msg": "ensure this value is less than or equal to 100",
111 "ctx": {"limit_value": 100},
112 },
113 {
114 "type": "value_error.number.not_ge",
115 "loc": ["query", "offset"],
116 "msg": "ensure this value is greater than or equal to 0",
117 "ctx": {"limit_value": 0},
118 },
119 {
120 "type": "value_error.const",
121 "loc": ["query", "order_by"],
122 "msg": "unexpected value; permitted: 'created_at', 'updated_at'",
123 "ctx": {
124 "given": "invalid",
125 "permitted": ["created_at", "updated_at"],
126 },
127 },
128 ]
129 }
130 )
131 )
134def test_query_param_model_extra(client: TestClient): 1abcde
135 response = client.get( 1uvwxy
136 "/items/",
137 params={
138 "limit": 10,
139 "offset": 5,
140 "order_by": "updated_at",
141 "tags": ["tag1", "tag2"],
142 "tool": "plumbus",
143 },
144 )
145 assert response.status_code == 422 1uvwxy
146 assert response.json() == snapshot( 1uvwxy
147 {
148 "detail": [
149 IsDict(
150 {
151 "type": "extra_forbidden",
152 "loc": ["query", "tool"],
153 "msg": "Extra inputs are not permitted",
154 "input": "plumbus",
155 }
156 )
157 | IsDict(
158 # TODO: remove when deprecating Pydantic v1
159 {
160 "type": "value_error.extra",
161 "loc": ["query", "tool"],
162 "msg": "extra fields not permitted",
163 }
164 )
165 ]
166 }
167 )
170def test_openapi_schema(client: TestClient): 1abcde
171 response = client.get("/openapi.json") 1zABCD
172 assert response.status_code == 200, response.text 1zABCD
173 assert response.json() == snapshot( 1zABCD
174 {
175 "openapi": "3.1.0",
176 "info": {"title": "FastAPI", "version": "0.1.0"},
177 "paths": {
178 "/items/": {
179 "get": {
180 "summary": "Read Items",
181 "operationId": "read_items_items__get",
182 "parameters": [
183 {
184 "name": "limit",
185 "in": "query",
186 "required": False,
187 "schema": {
188 "type": "integer",
189 "maximum": 100,
190 "exclusiveMinimum": 0,
191 "default": 100,
192 "title": "Limit",
193 },
194 },
195 {
196 "name": "offset",
197 "in": "query",
198 "required": False,
199 "schema": {
200 "type": "integer",
201 "minimum": 0,
202 "default": 0,
203 "title": "Offset",
204 },
205 },
206 {
207 "name": "order_by",
208 "in": "query",
209 "required": False,
210 "schema": {
211 "enum": ["created_at", "updated_at"],
212 "type": "string",
213 "default": "created_at",
214 "title": "Order By",
215 },
216 },
217 {
218 "name": "tags",
219 "in": "query",
220 "required": False,
221 "schema": {
222 "type": "array",
223 "items": {"type": "string"},
224 "default": [],
225 "title": "Tags",
226 },
227 },
228 ],
229 "responses": {
230 "200": {
231 "description": "Successful Response",
232 "content": {"application/json": {"schema": {}}},
233 },
234 "422": {
235 "description": "Validation Error",
236 "content": {
237 "application/json": {
238 "schema": {
239 "$ref": "#/components/schemas/HTTPValidationError"
240 }
241 }
242 },
243 },
244 },
245 }
246 }
247 },
248 "components": {
249 "schemas": {
250 "HTTPValidationError": {
251 "properties": {
252 "detail": {
253 "items": {
254 "$ref": "#/components/schemas/ValidationError"
255 },
256 "type": "array",
257 "title": "Detail",
258 }
259 },
260 "type": "object",
261 "title": "HTTPValidationError",
262 },
263 "ValidationError": {
264 "properties": {
265 "loc": {
266 "items": {
267 "anyOf": [{"type": "string"}, {"type": "integer"}]
268 },
269 "type": "array",
270 "title": "Location",
271 },
272 "msg": {"type": "string", "title": "Message"},
273 "type": {"type": "string", "title": "Error Type"},
274 },
275 "type": "object",
276 "required": ["loc", "msg", "type"],
277 "title": "ValidationError",
278 },
279 }
280 },
281 }
282 )