|
9 | 9 | from typing import Any
|
10 | 10 | import importlib
|
11 | 11 | import logging
|
12 |
| -import pytest |
| 12 | +import pytest # for explicit fail calls, see _pytestFail |
| 13 | +import json |
| 14 | +import dataclasses |
13 | 15 |
|
14 | 16 | log = logging.getLogger("flask_tester")
|
15 | 17 |
|
@@ -346,17 +348,56 @@ def request(self, method: str, path: str, status: int|None = None, content: str|
|
346 | 348 | cookies.update(kwargs["cookies"])
|
347 | 349 | del kwargs["cookies"]
|
348 | 350 |
|
| 351 | + # FIXME allow or forbid? |
| 352 | + # if "json" in kwargs and "data" in kwargs: |
| 353 | + # log.warning("mix of json and data parameters in request") |
| 354 | + |
| 355 | + # convert json parameters |
| 356 | + if "json" in kwargs: |
| 357 | + json_param = kwargs["json"] |
| 358 | + assert isinstance(json_param, dict) |
| 359 | + for name in list(json_param.keys()): |
| 360 | + val = json_param[name] |
| 361 | + if val is None: |
| 362 | + pass |
| 363 | + elif isinstance(val, (bool, int, float, str, tuple, list, dict)): |
| 364 | + pass |
| 365 | + elif "model_dump" in val.__dir__() and callable(val.model_dump): |
| 366 | + # probably pydantic |
| 367 | + json_param[name] = val.model_dump() |
| 368 | + else: # pydantic or standard dataclasses? |
| 369 | + json_param[name] = dataclasses.asdict(val) |
| 370 | + |
| 371 | + # convert data parameters |
| 372 | + if "data" in kwargs: |
| 373 | + data_param = kwargs["data"] |
| 374 | + assert isinstance(data_param, dict) |
| 375 | + for name in list(data_param.keys()): |
| 376 | + val = data_param[name] |
| 377 | + if val is None: |
| 378 | + data_param[name] = "null" |
| 379 | + elif isinstance(val, (io.IOBase, tuple)): |
| 380 | + pass # file parameters? |
| 381 | + elif isinstance(val, (bool, int, float, str, list, dict)): |
| 382 | + data_param[name] = json.dumps(val) |
| 383 | + elif "model_dump_json" in val.__dir__() and callable(val.model_dump_json): |
| 384 | + data_param[name] = val.model_dump_json() |
| 385 | + else: |
| 386 | + data_param[name] = json.dumps(dataclasses.asdict(val)) |
| 387 | + |
349 | 388 | self._auth.setAuth(login, kwargs, cookies, auth=auth)
|
350 | 389 | res = self._request(method, path, cookies, **kwargs) # type: ignore
|
351 | 390 |
|
352 | 391 | # check status
|
353 | 392 | if status is not None:
|
354 | 393 | if res.status_code != status: # show error before aborting
|
| 394 | + # FIXME what if the useful part is at the end? |
355 | 395 | _pytestFail(f"bad {status} result: {res.status_code} {res.text[:512]}...")
|
356 | 396 |
|
357 | 397 | # check content
|
358 | 398 | if content is not None:
|
359 | 399 | if not re.search(content, res.text, re.DOTALL):
|
| 400 | + # FIXME what if the useful part is at the end? |
360 | 401 | _pytestFail(f"cannot find {content} in {res.text[:512]}...")
|
361 | 402 |
|
362 | 403 | return res
|
|
0 commit comments