From 1f77549e28290e1b6aff198f40c45f5bb8e1e2de Mon Sep 17 00:00:00 2001 From: Suren Khorenyan Date: Sun, 9 Jun 2024 17:34:44 +0300 Subject: [PATCH] refactor tests for validators and mark as xfail --- tests/test_api/test_validators.py | 72 ++++++++++++++++--------------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/tests/test_api/test_validators.py b/tests/test_api/test_validators.py index 91898c49..9bf9c101 100644 --- a/tests/test_api/test_validators.py +++ b/tests/test_api/test_validators.py @@ -1,10 +1,16 @@ from copy import deepcopy -from typing import Dict, List, Optional, Set, Type +from typing import ( + Type, + Annotated, +) import pytest from fastapi import FastAPI, status from httpx import AsyncClient -from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator + +from fastapi_jsonapi.types_metadata import ClientCanSetId +from fastapi_jsonapi.views.view_base import ViewBase +from pydantic import BaseModel, ConfigDict, field_validator, model_validator from pytest import mark, param # noqa: PT013 from pytest_asyncio import fixture from sqlalchemy.ext.asyncio import AsyncSession @@ -24,6 +30,9 @@ pytestmark = pytest.mark.asyncio +# TODO: Support Annotated validators (Before/After) + + @fixture() async def task_with_none_ids( async_session: AsyncSession, @@ -40,6 +49,7 @@ def resource_type(): return "task" +@pytest.mark.xfail(reason="validators passthrough not supported yet") class TestTaskValidators: async def test_base_model_validator_pre_true_get_one( self, @@ -56,7 +66,7 @@ async def test_base_model_validator_pre_true_get_one( attributes = response_data["data"].pop("attributes") assert response_data == { "data": { - "id": str(task_with_none_ids.id), + "id": ViewBase.get_db_item_id(task_with_none_ids), "type": resource_type, }, "jsonapi": {"version": "1.0"}, @@ -81,26 +91,18 @@ async def test_base_model_root_validator_get_list( res = await client.get(url) assert res.status_code == status.HTTP_200_OK, res.text response_data = res.json() - assert response_data == { - "data": [ - { - "id": str(task_with_none_ids.id), - "type": resource_type, - "attributes": { - # not `None`! schema validator returns empty list `[]` - # "task_ids": None, - "task_ids": [], - }, + expected_data = [ + { + "id": ViewBase.get_db_item_id(task_with_none_ids), + "type": resource_type, + "attributes": { + # not `None`! schema validator returns empty list `[]` + # "task_ids": None, + "task_ids": [], }, - ], - "jsonapi": { - "version": "1.0", }, - "meta": { - "count": 1, - "totalPages": 1, - }, - } + ] + assert response_data["data"] == expected_data async def test_base_model_root_validator_create( self, @@ -126,7 +128,6 @@ async def test_base_model_root_validator_create( task_id = response_data["data"].pop("id") task = await async_session.get(Task, int(task_id)) assert isinstance(task, Task) - assert task.task_ids == [] # we sent request with `None`, but value in db is `[]` # because validator converted data before object creation assert task.task_ids == [] @@ -143,6 +144,7 @@ async def test_base_model_root_validator_create( } +@pytest.mark.xfail(reason="validators passthrough not supported yet") class TestValidators: resource_type = "validator" @@ -162,12 +164,10 @@ def _refresh_caches(self) -> None: RoutersJSONAPI.all_jsonapi_routers = all_jsonapi_routers - def build_app(self, schema, resource_type: Optional[str] = None) -> FastAPI: + def build_app(self, schema, resource_type: str | None = None) -> FastAPI: return build_app_custom( model=User, schema=schema, - # schema_in_post=schema, - # schema_in_patch=schema, resource_type=resource_type or self.resource_type, ) @@ -180,9 +180,9 @@ class InheritedSchema(schema): async def execute_request_and_check_response( self, app: FastAPI, - body: Dict, + body: dict, expected_detail: str, - resource_type: Optional[str] = None, + resource_type: str | None = None, ): resource_type = resource_type or self.resource_type async with AsyncClient(app=app, base_url="http://test") as client: @@ -203,7 +203,7 @@ async def execute_request_and_check_response( async def execute_request_twice_and_check_response( self, schema: Type[BaseModel], - body: Dict, + body: dict, expected_detail: str, ): """ @@ -251,7 +251,7 @@ def validate_name(cls, v): async def test_field_validator_each_item_arg(self): class UserSchemaWithValidator(BaseModel): - names: List[str] + names: list[str] @field_validator("names") @classmethod @@ -273,7 +273,7 @@ def validate_name(cls, v): async def test_field_validator_pre_arg(self): class UserSchemaWithValidator(BaseModel): - name: List[str] + name: list[str] @field_validator("name", mode="before") @classmethod @@ -400,7 +400,8 @@ async def test_check_validator_for_id_field(self): """ class UserSchemaWithValidator(BaseModel): - id: int = Field(json_schema_extra={"client_can_set_id": True}) + # TODO + id: Annotated[int, ClientCanSetId()] @field_validator("id") @classmethod @@ -412,7 +413,7 @@ def validate_id(cls, v): create_user_body = { "data": { "attributes": {}, - "id": 42, + "id": str(42), }, } @@ -653,6 +654,7 @@ def validator_post_2(cls, values): ) +@pytest.mark.xfail(reason="validators passthrough not supported yet") class TestValidationUtils: @mark.parametrize( ("include", "exclude", "expected"), @@ -665,9 +667,9 @@ class TestValidationUtils: ) def test_extract_field_validators_args( self, - include: Set[str], - exclude: Set[str], - expected: Set[str], + exclude: set[str], + include: set[str], + expected: set[str], ): class ValidationSchema(BaseModel): item_1: str