Add comprehensive test suite: 219 new tests across backend and frontend
Backend (103 tests): - Unit tests for listing_service, export_service, district_service - Regression tests for API response contracts and query parameter validation - Integration tests for API workflows, Redis listing cache, listing processor pipeline, and repository advanced queries - E2E tests for streaming with filters, batching, caching, and task management Frontend (116 tests): - Service tests for apiClient, streamingService, taskService, listingService, healthService - Hook tests for useTaskProgress (WebSocket + polling) - Component tests for PropertyCard, FilterPanel, Header, ListView, TaskProgressDrawer, TaskIndicator, StreamingProgressBar, HealthIndicator - E2E tests for filter-stream-display flow Infrastructure: - Add pytest-xdist and test markers (regression, integration, e2e) - Add conftest fixtures: fake_redis, rent_listing_factory, seeded_repository - Add vitest + testing-library + MSW for frontend testing
This commit is contained in:
parent
a3ac9cc060
commit
8d22c97320
36 changed files with 5447 additions and 19 deletions
87
tests/unit/test_export_service.py
Normal file
87
tests/unit/test_export_service.py
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
"""Unit tests for services/export_service.py."""
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from models.listing import QueryParameters, ListingType
|
||||
from services import export_service
|
||||
|
||||
|
||||
class TestExportToCsv:
|
||||
async def test_csv_export_calls_exporter(self, listing_repository, tmp_path):
|
||||
output_path = tmp_path / "output.csv"
|
||||
with patch("csv_exporter.export_to_csv", new_callable=AsyncMock) as mock_csv:
|
||||
mock_csv.return_value = None
|
||||
result = await export_service.export_to_csv(listing_repository, output_path)
|
||||
mock_csv.assert_called_once()
|
||||
assert result.success
|
||||
|
||||
async def test_csv_export_returns_correct_record_count(self, listing_repository, sample_rent_listings, tmp_path):
|
||||
await listing_repository.upsert_listings(sample_rent_listings)
|
||||
output_path = tmp_path / "output.csv"
|
||||
with patch("csv_exporter.export_to_csv", new_callable=AsyncMock) as mock_csv:
|
||||
mock_csv.return_value = None
|
||||
result = await export_service.export_to_csv(listing_repository, output_path)
|
||||
assert result.record_count == len(sample_rent_listings)
|
||||
|
||||
async def test_csv_export_passes_query_parameters(self, listing_repository, tmp_path):
|
||||
output_path = tmp_path / "output.csv"
|
||||
params = QueryParameters(listing_type=ListingType.RENT, min_bedrooms=2)
|
||||
with patch("csv_exporter.export_to_csv", new_callable=AsyncMock) as mock_csv:
|
||||
mock_csv.return_value = None
|
||||
result = await export_service.export_to_csv(
|
||||
listing_repository, output_path, query_parameters=params
|
||||
)
|
||||
assert result.success
|
||||
assert str(output_path) in result.output_path
|
||||
|
||||
|
||||
class TestExportToGeojson:
|
||||
async def test_geojson_in_memory_returns_data(self, listing_repository):
|
||||
fake_geojson = {"type": "FeatureCollection", "features": [{"type": "Feature"}]}
|
||||
with patch("ui_exporter.export_immoweb", new_callable=AsyncMock) as mock_export:
|
||||
mock_export.return_value = fake_geojson
|
||||
result = await export_service.export_to_geojson(listing_repository)
|
||||
assert result.data is not None
|
||||
assert result.data["type"] == "FeatureCollection"
|
||||
|
||||
async def test_geojson_file_export_returns_path(self, listing_repository, tmp_path):
|
||||
output_path = tmp_path / "output.geojson"
|
||||
fake_geojson = {"type": "FeatureCollection", "features": []}
|
||||
with patch("ui_exporter.export_immoweb", new_callable=AsyncMock) as mock_export:
|
||||
mock_export.return_value = fake_geojson
|
||||
result = await export_service.export_to_geojson(
|
||||
listing_repository, output_path=output_path
|
||||
)
|
||||
assert result.output_path is not None
|
||||
assert result.data is None
|
||||
|
||||
async def test_geojson_with_filters(self, listing_repository):
|
||||
params = QueryParameters(listing_type=ListingType.RENT, min_bedrooms=2)
|
||||
fake_geojson = {"type": "FeatureCollection", "features": []}
|
||||
with patch("ui_exporter.export_immoweb", new_callable=AsyncMock) as mock_export:
|
||||
mock_export.return_value = fake_geojson
|
||||
result = await export_service.export_to_geojson(
|
||||
listing_repository, query_parameters=params
|
||||
)
|
||||
assert result.success
|
||||
mock_export.assert_called_once()
|
||||
|
||||
async def test_geojson_with_limit(self, listing_repository):
|
||||
fake_geojson = {"type": "FeatureCollection", "features": []}
|
||||
with patch("ui_exporter.export_immoweb", new_callable=AsyncMock) as mock_export:
|
||||
mock_export.return_value = fake_geojson
|
||||
result = await export_service.export_to_geojson(
|
||||
listing_repository, limit=5
|
||||
)
|
||||
assert result.success
|
||||
_, kwargs = mock_export.call_args
|
||||
assert kwargs.get("limit") == 5
|
||||
|
||||
async def test_geojson_empty_data(self, listing_repository):
|
||||
fake_geojson = {"type": "FeatureCollection", "features": []}
|
||||
with patch("ui_exporter.export_immoweb", new_callable=AsyncMock) as mock_export:
|
||||
mock_export.return_value = fake_geojson
|
||||
result = await export_service.export_to_geojson(listing_repository)
|
||||
assert result.record_count == 0
|
||||
Loading…
Add table
Add a link
Reference in a new issue