fix: ruff lint + format fixes in tests, ESLint fixes in frontend

This commit is contained in:
2026-07-17 21:28:58 +02:00
parent 341d0c6f38
commit fbb1b39b57
56 changed files with 1399 additions and 721 deletions
+88 -65
View File
@@ -5,12 +5,10 @@ from unittest.mock import AsyncMock, MagicMock, patch
import pytest
import pytest_asyncio
from httpx import ASGITransport, AsyncClient
from httpx import AsyncClient
from sqlalchemy.ext.asyncio import AsyncSession
from app.database import Base, get_db
from app.main import app
from app.models.retouch import RetouchResult, RetouchStatus
from app.models.retouch import RetouchStatus
from app.models.vehicle import Vehicle
from app.services import retouch_service, price_compare_service
@@ -83,7 +81,9 @@ class TestRetouchService:
assert "red" in prompt
@pytest.mark.asyncio
async def test_upload_retouch_file_success(self, db_session: AsyncSession, tmp_path):
async def test_upload_retouch_file_success(
self, db_session: AsyncSession, tmp_path
):
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
result = await retouch_service.upload_retouch_file(
db=db_session,
@@ -132,12 +132,16 @@ class TestRetouchService:
async def test_list_results_with_data(self, db_session: AsyncSession, tmp_path):
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
await retouch_service.upload_retouch_file(
db=db_session, file_bytes=_fake_image(),
file_name="img1.png", mime_type="image/png",
db=db_session,
file_bytes=_fake_image(),
file_name="img1.png",
mime_type="image/png",
)
await retouch_service.upload_retouch_file(
db=db_session, file_bytes=_fake_image(),
file_name="img2.png", mime_type="image/png",
db=db_session,
file_bytes=_fake_image(),
file_name="img2.png",
mime_type="image/png",
)
await db_session.commit()
items, total = await retouch_service.list_results(db_session)
@@ -150,13 +154,17 @@ class TestRetouchService:
):
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
await retouch_service.upload_retouch_file(
db=db_session, file_bytes=_fake_image(),
file_name="img1.png", mime_type="image/png",
db=db_session,
file_bytes=_fake_image(),
file_name="img1.png",
mime_type="image/png",
vehicle_id=test_vehicle.id,
)
await retouch_service.upload_retouch_file(
db=db_session, file_bytes=_fake_image(),
file_name="img2.png", mime_type="image/png",
db=db_session,
file_bytes=_fake_image(),
file_name="img2.png",
mime_type="image/png",
)
await db_session.commit()
items, total = await retouch_service.list_results(
@@ -171,20 +179,22 @@ class TestRetouchService:
"""Test process_retouch with mocked Flux.1-Pro call."""
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
result = await retouch_service.upload_retouch_file(
db=db_session, file_bytes=_fake_image(),
file_name="truck.png", mime_type="image/png",
db=db_session,
file_bytes=_fake_image(),
file_name="truck.png",
mime_type="image/png",
)
await db_session.commit()
# Mock the _call_flux_pro function to return fake retouched bytes
retouched_bytes = b"\x89PNG\r\n\x1a\n" + b"\xFF" * 1016
retouched_bytes = b"\x89PNG\r\n\x1a\n" + b"\xff" * 1016
with patch.object(
retouch_service, "_call_flux_pro",
new_callable=AsyncMock, return_value=retouched_bytes,
retouch_service,
"_call_flux_pro",
new_callable=AsyncMock,
return_value=retouched_bytes,
):
processed = await retouch_service.process_retouch(
db_session, result.id
)
processed = await retouch_service.process_retouch(db_session, result.id)
await db_session.commit()
assert processed.status == RetouchStatus.completed.value
@@ -197,19 +207,20 @@ class TestRetouchService:
"""Test process_retouch sets failed status on OpenRouter error."""
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
result = await retouch_service.upload_retouch_file(
db=db_session, file_bytes=_fake_image(),
file_name="truck.png", mime_type="image/png",
db=db_session,
file_bytes=_fake_image(),
file_name="truck.png",
mime_type="image/png",
)
await db_session.commit()
with patch.object(
retouch_service, "_call_flux_pro",
retouch_service,
"_call_flux_pro",
new_callable=AsyncMock,
side_effect=Exception("OpenRouter unavailable"),
):
processed = await retouch_service.process_retouch(
db_session, result.id
)
processed = await retouch_service.process_retouch(db_session, result.id)
await db_session.commit()
assert processed.status == RetouchStatus.failed.value
@@ -227,7 +238,9 @@ class TestRetouchService:
async def test_call_flux_pro_no_api_key(self):
"""Test _call_flux_pro raises ValueError when no API key configured."""
with patch.object(retouch_service.settings, "OPENROUTER_API_KEY", ""):
with pytest.raises(ValueError, match="OPENROUTER_API_KEY is not configured"):
with pytest.raises(
ValueError, match="OPENROUTER_API_KEY is not configured"
):
await retouch_service._call_flux_pro(
image_bytes=b"fake-image",
mime_type="image/png",
@@ -235,9 +248,12 @@ class TestRetouchService:
)
@pytest.mark.asyncio
async def test_call_flux_pro_success_data_uri(self, db_session: AsyncSession, tmp_path):
async def test_call_flux_pro_success_data_uri(
self, db_session: AsyncSession, tmp_path
):
"""Test _call_flux_pro with mocked httpx returning base64 data URI."""
import base64 as b64mod
retouched = b"\x89PNG\r\n\x1a\nretouched-data"
b64_retouched = b64mod.b64encode(retouched).decode("utf-8")
@@ -245,11 +261,7 @@ class TestRetouchService:
mock_response.raise_for_status = MagicMock()
mock_response.json.return_value = {
"choices": [
{
"message": {
"content": f"data:image/png;base64,{b64_retouched}"
}
}
{"message": {"content": f"data:image/png;base64,{b64_retouched}"}}
]
}
@@ -259,7 +271,10 @@ class TestRetouchService:
mock_client.__aexit__ = AsyncMock(return_value=None)
with patch.object(retouch_service.settings, "OPENROUTER_API_KEY", "test-key"):
with patch("app.services.retouch_service.httpx.AsyncClient", return_value=mock_client):
with patch(
"app.services.retouch_service.httpx.AsyncClient",
return_value=mock_client,
):
result = await retouch_service._call_flux_pro(
image_bytes=b"fake-image",
mime_type="image/png",
@@ -268,9 +283,12 @@ class TestRetouchService:
assert result == retouched
@pytest.mark.asyncio
async def test_call_flux_pro_success_list_content(self, db_session: AsyncSession, tmp_path):
async def test_call_flux_pro_success_list_content(
self, db_session: AsyncSession, tmp_path
):
"""Test _call_flux_pro with content as list of parts."""
import base64 as b64mod
retouched = b"\x89PNG\r\n\x1a\nlist-content"
b64_retouched = b64mod.b64encode(retouched).decode("utf-8")
@@ -282,7 +300,12 @@ class TestRetouchService:
"message": {
"content": [
{"type": "text", "text": "Here is the image"},
{"type": "image_url", "image_url": {"url": f"data:image/png;base64,{b64_retouched}"}},
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{b64_retouched}"
},
},
]
}
}
@@ -295,7 +318,10 @@ class TestRetouchService:
mock_client.__aexit__ = AsyncMock(return_value=None)
with patch.object(retouch_service.settings, "OPENROUTER_API_KEY", "test-key"):
with patch("app.services.retouch_service.httpx.AsyncClient", return_value=mock_client):
with patch(
"app.services.retouch_service.httpx.AsyncClient",
return_value=mock_client,
):
result = await retouch_service._call_flux_pro(
image_bytes=b"fake-image",
mime_type="image/png",
@@ -309,13 +335,7 @@ class TestRetouchService:
mock_response = MagicMock()
mock_response.raise_for_status = MagicMock()
mock_response.json.return_value = {
"choices": [
{
"message": {
"content": "Sorry, I cannot process this image."
}
}
]
"choices": [{"message": {"content": "Sorry, I cannot process this image."}}]
}
mock_client = AsyncMock()
@@ -325,7 +345,10 @@ class TestRetouchService:
original = b"original-image-bytes"
with patch.object(retouch_service.settings, "OPENROUTER_API_KEY", "test-key"):
with patch("app.services.retouch_service.httpx.AsyncClient", return_value=mock_client):
with patch(
"app.services.retouch_service.httpx.AsyncClient",
return_value=mock_client,
):
result = await retouch_service._call_flux_pro(
image_bytes=original,
mime_type="image/png",
@@ -341,9 +364,7 @@ class TestPriceCompareService:
async def test_compare_prices_success(
self, db_session: AsyncSession, test_vehicle: Vehicle
):
result = await price_compare_service.compare_prices(
db_session, test_vehicle.id
)
result = await price_compare_service.compare_prices(db_session, test_vehicle.id)
assert result.vehicle_id == test_vehicle.id
assert len(result.comparable_listings) > 0
assert result.average_price is not None
@@ -355,17 +376,13 @@ class TestPriceCompareService:
@pytest.mark.asyncio
async def test_compare_prices_vehicle_not_found(self, db_session: AsyncSession):
with pytest.raises(ValueError, match="not found"):
await price_compare_service.compare_prices(
db_session, uuid.uuid4()
)
await price_compare_service.compare_prices(db_session, uuid.uuid4())
@pytest.mark.asyncio
async def test_compare_prices_listings_have_correct_make_model(
self, db_session: AsyncSession, test_vehicle: Vehicle
):
result = await price_compare_service.compare_prices(
db_session, test_vehicle.id
)
result = await price_compare_service.compare_prices(db_session, test_vehicle.id)
for listing in result.comparable_listings:
assert listing.make == test_vehicle.make
assert listing.model == test_vehicle.model
@@ -375,10 +392,10 @@ class TestPriceCompareService:
async def test_compare_prices_average_calculation(
self, db_session: AsyncSession, test_vehicle: Vehicle
):
result = await price_compare_service.compare_prices(
db_session, test_vehicle.id
)
expected_avg = sum(l.price for l in result.comparable_listings) / len(result.comparable_listings)
result = await price_compare_service.compare_prices(db_session, test_vehicle.id)
expected_avg = sum(
listing.price for listing in result.comparable_listings
) / len(result.comparable_listings)
assert abs(result.average_price - round(expected_avg, 2)) < 0.01
@@ -447,8 +464,10 @@ class TestRetouchRouter:
"""GET /retouch/results/:id returns 200 with completed status."""
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
result = await retouch_service.upload_retouch_file(
db=db_session, file_bytes=_fake_image(),
file_name="truck.png", mime_type="image/png",
db=db_session,
file_bytes=_fake_image(),
file_name="truck.png",
mime_type="image/png",
)
result.status = RetouchStatus.completed.value
result.retouched_file_path = str(tmp_path / "retouched.png")
@@ -468,8 +487,10 @@ class TestRetouchRouter:
"""GET /retouch/results/:id before completion returns 200 with processing status."""
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
result = await retouch_service.upload_retouch_file(
db=db_session, file_bytes=_fake_image(),
file_name="truck.png", mime_type="image/png",
db=db_session,
file_bytes=_fake_image(),
file_name="truck.png",
mime_type="image/png",
)
result.status = RetouchStatus.processing.value
await db_session.commit()
@@ -487,8 +508,10 @@ class TestRetouchRouter:
"""GET /retouch/results/:id with failed status returns 200 + error."""
with patch.object(retouch_service.settings, "UPLOAD_DIR", str(tmp_path)):
result = await retouch_service.upload_retouch_file(
db=db_session, file_bytes=_fake_image(),
file_name="truck.png", mime_type="image/png",
db=db_session,
file_bytes=_fake_image(),
file_name="truck.png",
mime_type="image/png",
)
result.status = RetouchStatus.failed.value
result.error_message = "OpenRouter unavailable"