"""Tests for analytics fixes to ensure all transactions are used in statistics.""" import pytest from datetime import datetime, timedelta from unittest.mock import Mock, AsyncMock from fastapi.testclient import TestClient from leggend.main import create_app from leggend.services.database_service import DatabaseService class TestAnalyticsFix: """Test analytics fixes for transaction limits""" @pytest.fixture def client(self): app = create_app() return TestClient(app) @pytest.fixture def mock_database_service(self): return Mock(spec=DatabaseService) @pytest.mark.asyncio async def test_transaction_stats_uses_all_transactions(self, client, mock_database_service): """Test that transaction stats endpoint uses all transactions (not limited to 100)""" # Mock data for 600 transactions (simulating the issue) mock_transactions = [] for i in range(600): mock_transactions.append({ "transactionId": f"txn-{i}", "transactionDate": (datetime.now() - timedelta(days=i % 365)).isoformat(), "description": f"Transaction {i}", "transactionValue": 10.0 if i % 2 == 0 else -5.0, "transactionCurrency": "EUR", "transactionStatus": "booked", "accountId": f"account-{i % 3}", }) mock_database_service.get_transactions_from_db = AsyncMock(return_value=mock_transactions) # Test that the endpoint calls get_transactions_from_db with limit=None with client as test_client: # Replace the database service in the route handler from leggend.api.routes import transactions original_service = transactions.database_service transactions.database_service = mock_database_service try: response = test_client.get("/api/v1/transactions/stats?days=365") assert response.status_code == 200 data = response.json() # Verify that limit=None was passed to get all transactions mock_database_service.get_transactions_from_db.assert_called_once() call_args = mock_database_service.get_transactions_from_db.call_args assert call_args.kwargs.get("limit") is None, "Stats endpoint should pass limit=None to get all transactions" # Verify that the response contains stats for all 600 transactions assert data["success"] is True stats = data["data"] assert stats["total_transactions"] == 600, "Should process all 600 transactions, not just 100" # Verify calculations are correct for all transactions expected_income = sum(txn["transactionValue"] for txn in mock_transactions if txn["transactionValue"] > 0) expected_expenses = sum(abs(txn["transactionValue"]) for txn in mock_transactions if txn["transactionValue"] < 0) assert stats["total_income"] == expected_income assert stats["total_expenses"] == expected_expenses finally: # Restore original service transactions.database_service = original_service @pytest.mark.asyncio async def test_analytics_endpoint_returns_all_transactions(self, client, mock_database_service): """Test that the new analytics endpoint returns all transactions without pagination""" # Mock data for 600 transactions mock_transactions = [] for i in range(600): mock_transactions.append({ "transactionId": f"txn-{i}", "transactionDate": (datetime.now() - timedelta(days=i % 365)).isoformat(), "description": f"Transaction {i}", "transactionValue": 10.0 if i % 2 == 0 else -5.0, "transactionCurrency": "EUR", "transactionStatus": "booked", "accountId": f"account-{i % 3}", }) mock_database_service.get_transactions_from_db = AsyncMock(return_value=mock_transactions) with client as test_client: # Replace the database service in the route handler from leggend.api.routes import transactions original_service = transactions.database_service transactions.database_service = mock_database_service try: response = test_client.get("/api/v1/transactions/analytics?days=365") assert response.status_code == 200 data = response.json() # Verify that limit=None was passed to get all transactions mock_database_service.get_transactions_from_db.assert_called_once() call_args = mock_database_service.get_transactions_from_db.call_args assert call_args.kwargs.get("limit") is None, "Analytics endpoint should pass limit=None" # Verify that all 600 transactions are returned assert data["success"] is True transactions_data = data["data"] assert len(transactions_data) == 600, "Analytics endpoint should return all 600 transactions" finally: # Restore original service transactions.database_service = original_service