chore: Update telegram bot tests and validate command
- Refactor telegram bot tests (remove old, add new real flow tests) - Add conftest.py for telegram bot test fixtures - Update validate.md command 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
276
reports-app/telegram-bot/tests/test_flows_real.py
Normal file
276
reports-app/telegram-bot/tests/test_flows_real.py
Normal file
@@ -0,0 +1,276 @@
|
||||
# reports-app/telegram-bot/tests/test_flows_real.py
|
||||
"""
|
||||
REAL Integration Tests for complete user flows.
|
||||
|
||||
Tests end-to-end flows with REAL backend API and database.
|
||||
Requires:
|
||||
- Backend API running on localhost:8001
|
||||
- SQLite database with at least one linked user
|
||||
- SSH tunnel for Oracle (if backend needs it)
|
||||
|
||||
USAGE:
|
||||
pytest tests/test_flows_real.py -m integration -v
|
||||
"""
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
class TestAuthFlowReal:
|
||||
"""Tests for authentication flow with real backend"""
|
||||
|
||||
async def test_user_linking_check(self, backend_available, auth_data):
|
||||
"""Verify we can check if a user is linked"""
|
||||
assert auth_data is not None
|
||||
assert "telegram_user_id" in auth_data
|
||||
assert "jwt_token" in auth_data
|
||||
assert auth_data["jwt_token"] is not None
|
||||
|
||||
async def test_jwt_token_is_valid(self, backend_client, jwt_token):
|
||||
"""Verify JWT token can be used to make API calls"""
|
||||
companies = await backend_client.get_user_companies(jwt_token=jwt_token)
|
||||
|
||||
# Token should allow fetching companies
|
||||
assert companies is not None
|
||||
assert isinstance(companies, list)
|
||||
|
||||
async def test_auth_data_has_username(self, auth_data):
|
||||
"""Verify auth data includes Oracle username"""
|
||||
assert "oracle_username" in auth_data
|
||||
assert auth_data["oracle_username"] is not None
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
class TestDashboardFlowReal:
|
||||
"""Tests for dashboard data flow with real backend"""
|
||||
|
||||
async def test_get_dashboard_data(self, backend_client, jwt_token, test_company_id):
|
||||
"""Verify we can get dashboard data from backend"""
|
||||
dashboard_data = await backend_client.get_dashboard_data(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token
|
||||
)
|
||||
|
||||
assert dashboard_data is not None
|
||||
assert isinstance(dashboard_data, dict)
|
||||
|
||||
async def test_dashboard_to_formatted_output(self, backend_client, jwt_token, test_company_id, test_company_name):
|
||||
"""Verify complete flow: API data -> formatted output"""
|
||||
from app.bot.formatters import format_dashboard_response
|
||||
|
||||
# 1. Get real data
|
||||
data = await backend_client.get_dashboard_data(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token
|
||||
)
|
||||
|
||||
# 2. Format response
|
||||
formatted = format_dashboard_response(data, test_company_name)
|
||||
|
||||
# 3. Verify output
|
||||
assert isinstance(formatted, str)
|
||||
assert len(formatted) > 0
|
||||
# Should contain company name or some data
|
||||
assert test_company_name in formatted or "RON" in formatted or "lei" in formatted.lower()
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
class TestTreasuryFlowReal:
|
||||
"""Tests for treasury data flow with real backend"""
|
||||
|
||||
async def test_get_treasury_data(self, backend_client, jwt_token, test_company_id):
|
||||
"""Verify we can get treasury breakdown from backend"""
|
||||
treasury_data = await backend_client.get_treasury_breakdown(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token
|
||||
)
|
||||
|
||||
assert treasury_data is not None
|
||||
|
||||
async def test_treasury_breakdown_split(self, jwt_token, test_company_id):
|
||||
"""Verify treasury breakdown can be split into casa/banca"""
|
||||
from app.bot.helpers import get_treasury_breakdown_split
|
||||
|
||||
casa_data, banca_data = await get_treasury_breakdown_split(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token
|
||||
)
|
||||
|
||||
# Both should be returned (even if empty)
|
||||
assert casa_data is not None or banca_data is not None
|
||||
|
||||
async def test_treasury_casa_formatted(self, jwt_token, test_company_id, test_company_name):
|
||||
"""Verify casa formatting works with real data"""
|
||||
from app.bot.formatters import format_treasury_casa_response
|
||||
from app.bot.helpers import get_treasury_breakdown_split
|
||||
|
||||
# 1. Get and split data
|
||||
casa_data, _ = await get_treasury_breakdown_split(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token
|
||||
)
|
||||
|
||||
# 2. Format (even if empty)
|
||||
formatted = format_treasury_casa_response(casa_data or [], test_company_name)
|
||||
|
||||
assert isinstance(formatted, str)
|
||||
|
||||
async def test_treasury_banca_formatted(self, jwt_token, test_company_id, test_company_name):
|
||||
"""Verify banca formatting works with real data"""
|
||||
from app.bot.formatters import format_treasury_banca_response
|
||||
from app.bot.helpers import get_treasury_breakdown_split
|
||||
|
||||
# 1. Get and split data
|
||||
_, banca_data = await get_treasury_breakdown_split(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token
|
||||
)
|
||||
|
||||
# 2. Format (even if empty)
|
||||
formatted = format_treasury_banca_response(banca_data or [], test_company_name)
|
||||
|
||||
assert isinstance(formatted, str)
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
class TestInvoicesFlowReal:
|
||||
"""Tests for invoices data flow with real backend"""
|
||||
|
||||
async def test_get_invoices_clienti(self, backend_client, jwt_token, test_company_id):
|
||||
"""Verify we can get client invoices"""
|
||||
invoices = await backend_client.search_invoices(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token,
|
||||
filters={"partner_type": "CLIENTI", "only_unpaid": True}
|
||||
)
|
||||
|
||||
assert invoices is not None
|
||||
|
||||
async def test_get_invoices_furnizori(self, backend_client, jwt_token, test_company_id):
|
||||
"""Verify we can get supplier invoices"""
|
||||
invoices = await backend_client.search_invoices(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token,
|
||||
filters={"partner_type": "FURNIZORI", "only_unpaid": True}
|
||||
)
|
||||
|
||||
assert invoices is not None
|
||||
|
||||
async def test_invoices_formatted(self, backend_client, jwt_token, test_company_id, test_company_name):
|
||||
"""Verify invoices formatting works with real data"""
|
||||
from app.bot.formatters import format_invoices_response
|
||||
|
||||
# Get real invoices
|
||||
invoices = await backend_client.search_invoices(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token,
|
||||
filters={"partner_type": "CLIENTI", "only_unpaid": True, "page_size": 10}
|
||||
)
|
||||
|
||||
# Format response
|
||||
formatted = format_invoices_response(
|
||||
invoices=invoices.get("items", []) if isinstance(invoices, dict) else invoices,
|
||||
company_name=test_company_name,
|
||||
partner_type="CLIENTI"
|
||||
)
|
||||
|
||||
assert isinstance(formatted, str)
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
class TestCompanySelectionFlowReal:
|
||||
"""Tests for company selection flow with real backend"""
|
||||
|
||||
async def test_get_all_companies(self, backend_client, jwt_token):
|
||||
"""Verify we can get all user companies"""
|
||||
companies = await backend_client.get_user_companies(jwt_token=jwt_token)
|
||||
|
||||
assert companies is not None
|
||||
assert isinstance(companies, list)
|
||||
assert len(companies) > 0
|
||||
|
||||
async def test_search_companies_by_name(self, jwt_token, test_companies):
|
||||
"""Verify company search works"""
|
||||
from app.bot.helpers import search_companies_by_name
|
||||
|
||||
# Use first company name as search term
|
||||
first_company_name = test_companies[0].get("nume_firma", "")
|
||||
search_term = first_company_name[:4] if len(first_company_name) >= 4 else first_company_name
|
||||
|
||||
results = await search_companies_by_name(search_term, jwt_token)
|
||||
|
||||
assert results is not None
|
||||
assert isinstance(results, list)
|
||||
|
||||
async def test_create_company_keyboard(self, test_companies):
|
||||
"""Verify company selection keyboard creation"""
|
||||
from app.bot.helpers import create_company_selection_keyboard
|
||||
|
||||
keyboard = create_company_selection_keyboard(test_companies, max_buttons=5)
|
||||
|
||||
assert keyboard is not None
|
||||
assert hasattr(keyboard, "inline_keyboard")
|
||||
assert len(keyboard.inline_keyboard) > 0
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
class TestCacheFlowReal:
|
||||
"""Tests for cache behavior with real backend"""
|
||||
|
||||
async def test_cache_stats_available(self, backend_client, jwt_token):
|
||||
"""Verify cache stats endpoint works"""
|
||||
try:
|
||||
stats = await backend_client.get_cache_stats(jwt_token=jwt_token)
|
||||
assert stats is not None
|
||||
except Exception:
|
||||
# Cache stats may not be implemented
|
||||
pytest.skip("Cache stats endpoint not available")
|
||||
|
||||
async def test_repeated_dashboard_requests(self, backend_client, jwt_token, test_company_id):
|
||||
"""Verify repeated requests are handled (cache should help)"""
|
||||
import time
|
||||
|
||||
# First request
|
||||
start1 = time.time()
|
||||
data1 = await backend_client.get_dashboard_data(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token
|
||||
)
|
||||
time1 = time.time() - start1
|
||||
|
||||
# Second request
|
||||
start2 = time.time()
|
||||
data2 = await backend_client.get_dashboard_data(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token
|
||||
)
|
||||
time2 = time.time() - start2
|
||||
|
||||
# Both should succeed
|
||||
assert data1 is not None
|
||||
assert data2 is not None
|
||||
|
||||
print(f"First request: {time1:.3f}s, Second request: {time2:.3f}s")
|
||||
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.asyncio
|
||||
class TestTrialBalanceFlowReal:
|
||||
"""Tests for trial balance flow with real backend"""
|
||||
|
||||
async def test_get_trial_balance(self, backend_client, jwt_token, test_company_id):
|
||||
"""Verify we can get trial balance data"""
|
||||
try:
|
||||
data = await backend_client.get_trial_balance(
|
||||
company_id=test_company_id,
|
||||
jwt_token=jwt_token
|
||||
)
|
||||
assert data is not None
|
||||
except AttributeError:
|
||||
# Method may not exist on client
|
||||
pytest.skip("Trial balance method not available on client")
|
||||
Reference in New Issue
Block a user