This commit addresses the overly restrictive .gitignore pattern that was excluding all test files (test_*.py), including legitimate pytest and unittest test suites essential for code quality and CI/CD. Changes to .gitignore: - Added negation patterns !**/tests/test_*.py and !**/test_*.py to allow proper test files while still blocking temporary scripts - This enables pytest test suites to be tracked by git Added test files (17 files): Telegram Bot Tests (15 files): - reports-app/telegram-bot/tests/test_auth.py Tests for authentication and account linking flow - reports-app/telegram-bot/tests/test_callbacks.py Tests for callback query handlers - reports-app/telegram-bot/tests/test_formatters.py Tests for message formatting utilities - reports-app/telegram-bot/tests/test_formatters_extended.py Extended formatter tests - reports-app/telegram-bot/tests/test_handlers_menu.py Tests for menu handlers - reports-app/telegram-bot/tests/test_helpers.py Tests for helper functions - reports-app/telegram-bot/tests/test_helpers_extended.py Extended helper tests - reports-app/telegram-bot/tests/test_helpers_real.py Real integration tests for helpers - reports-app/telegram-bot/tests/test_helpers_real_simple.py Simplified integration tests - reports-app/telegram-bot/tests/test_login_flow.py Complete login flow integration tests - reports-app/telegram-bot/tests/test_menus.py Menu system tests - reports-app/telegram-bot/tests/test_session_company.py Session and company management tests - reports-app/telegram-bot/test_claude_integration.py Manual integration test (Claude AI) - reports-app/telegram-bot/test_claude_response.py Response formatting test - reports-app/telegram-bot/test_db.py Database operations manual test Shared Module Tests (2 files): - shared/auth/test_auth.py Authentication system tests - shared/database/test_pool.py Oracle connection pool tests Security verification: ✅ All test files use mock objects, fixtures, and environment variables ✅ No hardcoded credentials or secrets found ✅ Safe for version control 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
324 lines
11 KiB
Python
324 lines
11 KiB
Python
"""
|
|
SIMPLIFIED REAL Integration Test for FAZA 2
|
|
|
|
⚠️ MANUAL INTEGRATION TEST - Not run by default in CI/CD
|
|
|
|
This script:
|
|
1. Logs into backend with REAL credentials from environment variables
|
|
2. Gets REAL JWT token
|
|
3. Tests helper functions with REAL backend data
|
|
|
|
REQUIREMENTS:
|
|
- Backend API running on localhost:8001
|
|
- Environment variables: TEST_USERNAME, TEST_PASSWORD
|
|
- NO DATABASE DEPENDENCY - Direct API testing
|
|
|
|
USAGE:
|
|
# Set credentials
|
|
export TEST_USERNAME="your_username"
|
|
export TEST_PASSWORD="your_password"
|
|
|
|
# Run as script
|
|
python tests/test_helpers_real_simple.py
|
|
|
|
# Run via pytest (requires --run-integration or -m integration)
|
|
pytest tests/test_helpers_real_simple.py -m integration
|
|
|
|
NOTE: This test is marked as @pytest.mark.integration and skipped by default.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
import asyncio
|
|
import logging
|
|
import os
|
|
import sys
|
|
import httpx
|
|
|
|
# Add parent directory to path
|
|
sys.path.insert(0, '/mnt/e/proiecte/roa2web/roa2web/reports-app/telegram-bot')
|
|
|
|
from app.bot.helpers import (
|
|
search_companies_by_name,
|
|
create_company_selection_keyboard,
|
|
format_company_context_footer
|
|
)
|
|
from app.api.client import get_backend_client
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def get_real_jwt_token() -> str:
|
|
"""
|
|
Login to backend and get REAL JWT token.
|
|
|
|
Uses actual backend credentials to authenticate.
|
|
Returns JWT access token.
|
|
"""
|
|
print("\n📝 Logging into backend to get REAL JWT token...")
|
|
|
|
# REAL credentials for Oracle backend (MUST be set in environment)
|
|
username = os.getenv("TEST_USERNAME")
|
|
password = os.getenv("TEST_PASSWORD")
|
|
|
|
if not username or not password:
|
|
raise ValueError(
|
|
"Integration tests require TEST_USERNAME and TEST_PASSWORD environment variables.\n"
|
|
"Set them in your shell or .env file before running integration tests."
|
|
)
|
|
|
|
try:
|
|
async with httpx.AsyncClient(base_url="http://localhost:8001") as client:
|
|
response = await client.post(
|
|
"/api/auth/login",
|
|
json={
|
|
"username": username,
|
|
"password": password
|
|
}
|
|
)
|
|
|
|
response.raise_for_status()
|
|
data = response.json()
|
|
|
|
if 'access_token' in data:
|
|
token = data['access_token']
|
|
print(f"✅ Got REAL JWT token: {token[:30]}...")
|
|
return token
|
|
else:
|
|
print(f"❌ No access_token in response: {data}")
|
|
return None
|
|
|
|
except Exception as e:
|
|
print(f"❌ Login failed: {e}")
|
|
return None
|
|
|
|
|
|
@pytest.mark.integration
|
|
async def test_real_helpers():
|
|
"""
|
|
Integration test for helper functions with REAL backend data.
|
|
|
|
Requires:
|
|
- Backend API running on localhost:8001
|
|
- TEST_USERNAME and TEST_PASSWORD environment variables
|
|
|
|
This test is skipped by default. Run with: pytest -m integration
|
|
"""
|
|
print("\n" + "="*80)
|
|
print(" FAZA 2 - REAL INTEGRATION TEST (Simplified)")
|
|
print(" Testing with ACTUAL backend API at localhost:8001")
|
|
print("="*80)
|
|
|
|
# Step 1: Get JWT token
|
|
jwt_token = await get_real_jwt_token()
|
|
|
|
if not jwt_token:
|
|
print("\n❌ FAILED: Could not get JWT token")
|
|
print(" Make sure backend is running at localhost:8001")
|
|
print(" and credentials are correct")
|
|
return False
|
|
|
|
print(f"\n✅ Prerequisites OK - Backend connected, JWT token obtained")
|
|
|
|
all_tests_passed = True
|
|
|
|
# TEST 1: Search companies with REAL data
|
|
print("\n" + "="*80)
|
|
print("TEST 1: search_companies_by_name() with REAL backend")
|
|
print("="*80)
|
|
|
|
try:
|
|
# Get all companies first
|
|
client = get_backend_client()
|
|
async with client:
|
|
all_companies = await client.get_user_companies(jwt_token=jwt_token)
|
|
|
|
print(f"✅ Got {len(all_companies)} REAL companies from backend")
|
|
|
|
if all_companies:
|
|
print("\nFirst 5 companies:")
|
|
for i, comp in enumerate(all_companies[:5], 1):
|
|
print(f" {i}. ID:{comp.get('id_firma'):3} | {comp.get('name')} | CUI:{comp.get('fiscal_code', 'N/A')}")
|
|
|
|
# Test search by partial name
|
|
first_name = all_companies[0].get('name', '')
|
|
search_term = first_name[:4].upper() if len(first_name) >= 4 else first_name
|
|
|
|
print(f"\n--- Testing search with term: '{search_term}' ---")
|
|
results = await search_companies_by_name(search_term, jwt_token)
|
|
print(f"✅ Found {len(results)} matches")
|
|
|
|
# Test case-insensitive
|
|
results_lower = await search_companies_by_name(search_term.lower(), jwt_token)
|
|
if len(results) == len(results_lower):
|
|
print("✅ Case-insensitive search works!")
|
|
else:
|
|
print(f"❌ Case-insensitive FAILED: {len(results)} vs {len(results_lower)}")
|
|
all_tests_passed = False
|
|
|
|
print("\n✅ TEST 1 PASSED")
|
|
else:
|
|
print("⚠️ No companies found - cannot test search")
|
|
|
|
except Exception as e:
|
|
print(f"❌ TEST 1 FAILED: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
all_tests_passed = False
|
|
|
|
# TEST 2: Create keyboard with REAL data
|
|
print("\n" + "="*80)
|
|
print("TEST 2: create_company_selection_keyboard() with REAL data")
|
|
print("="*80)
|
|
|
|
try:
|
|
if all_companies:
|
|
keyboard = create_company_selection_keyboard(all_companies[:10], max_buttons=5)
|
|
|
|
print(f"✅ Created keyboard with {len(keyboard.inline_keyboard)} buttons")
|
|
|
|
# Check first few buttons
|
|
print("\nFirst 3 buttons:")
|
|
for i, row in enumerate(keyboard.inline_keyboard[:3], 1):
|
|
button = row[0]
|
|
print(f" {i}. {button.text[:50]}")
|
|
print(f" Callback: {button.callback_data}")
|
|
|
|
# Verify callback format
|
|
first_callback = keyboard.inline_keyboard[0][0].callback_data
|
|
if first_callback.startswith("select_company:"):
|
|
print("\n✅ Callback format correct")
|
|
else:
|
|
print(f"\n❌ Invalid callback: {first_callback}")
|
|
all_tests_passed = False
|
|
|
|
# Test with overflow
|
|
if len(all_companies) > 5:
|
|
keyboard_overflow = create_company_selection_keyboard(all_companies, max_buttons=5)
|
|
if len(keyboard_overflow.inline_keyboard) == 6: # 5 companies + overflow
|
|
print("✅ Overflow indicator works correctly")
|
|
else:
|
|
print(f"❌ Overflow FAILED: expected 6 buttons, got {len(keyboard_overflow.inline_keyboard)}")
|
|
all_tests_passed = False
|
|
|
|
print("\n✅ TEST 2 PASSED")
|
|
else:
|
|
print("⚠️ No companies - cannot test keyboard")
|
|
|
|
except Exception as e:
|
|
print(f"❌ TEST 2 FAILED: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
all_tests_passed = False
|
|
|
|
# TEST 3: Format footer with REAL company name
|
|
print("\n" + "="*80)
|
|
print("TEST 3: format_company_context_footer() with REAL data")
|
|
print("="*80)
|
|
|
|
try:
|
|
if all_companies:
|
|
company_name = all_companies[0].get('name')
|
|
footer = format_company_context_footer(company_name)
|
|
|
|
print(f"Company: {company_name}")
|
|
print(f"\nFormatted footer:")
|
|
print(repr(footer))
|
|
print("\nRendered:")
|
|
print(footer)
|
|
|
|
# Verify structure
|
|
checks = [
|
|
("Has separator", "━" in footer),
|
|
("Has emoji", "📊" in footer),
|
|
("Has company name", company_name in footer),
|
|
("Has command", "/selectcompany" in footer),
|
|
("Starts with newlines", footer.startswith("\n\n")),
|
|
("Is discrete", len(footer) < 150)
|
|
]
|
|
|
|
print("\nVerification:")
|
|
all_checks_passed = True
|
|
for check_name, passed in checks:
|
|
status = "✅" if passed else "❌"
|
|
print(f" {status} {check_name}")
|
|
if not passed:
|
|
all_checks_passed = False
|
|
all_tests_passed = False
|
|
|
|
if all_checks_passed:
|
|
print("\n✅ TEST 3 PASSED")
|
|
else:
|
|
print("\n❌ TEST 3 FAILED")
|
|
else:
|
|
print("⚠️ No companies - cannot test footer")
|
|
|
|
except Exception as e:
|
|
print(f"❌ TEST 3 FAILED: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
all_tests_passed = False
|
|
|
|
# BONUS TEST: Dashboard data
|
|
print("\n" + "="*80)
|
|
print("BONUS: Get REAL dashboard data (for FAZA 3 preparation)")
|
|
print("="*80)
|
|
|
|
try:
|
|
if all_companies:
|
|
company_id = all_companies[0].get('id_firma')
|
|
company_name = all_companies[0].get('name')
|
|
|
|
print(f"Company: {company_name} (ID: {company_id})")
|
|
|
|
async with get_backend_client() as client:
|
|
dashboard_data = await client.get_dashboard_data(
|
|
company_id=company_id,
|
|
jwt_token=jwt_token
|
|
)
|
|
|
|
if dashboard_data:
|
|
print(f"✅ Got REAL dashboard data!")
|
|
print(f"\nData keys: {list(dashboard_data.keys())[:10]}")
|
|
|
|
# Sample some values
|
|
sample_keys = ['sold_total', 'facturi_emise', 'facturi_platite']
|
|
print("\nSample values:")
|
|
for key in sample_keys:
|
|
if key in dashboard_data:
|
|
print(f" {key}: {dashboard_data[key]}")
|
|
|
|
print("\n✅ BONUS TEST PASSED - Dashboard data accessible!")
|
|
else:
|
|
print("⚠️ No dashboard data returned")
|
|
else:
|
|
print("⚠️ No companies - cannot test dashboard")
|
|
|
|
except Exception as e:
|
|
print(f"⚠️ BONUS TEST WARNING: {e}")
|
|
# Don't fail on bonus test
|
|
|
|
# SUMMARY
|
|
print("\n" + "="*80)
|
|
print(" SUMMARY")
|
|
print("="*80)
|
|
|
|
if all_tests_passed:
|
|
print("\n🎉 ALL TESTS PASSED!")
|
|
print("✅ FAZA 2 implementation is CORRECT with REAL data!")
|
|
print("\nHelper functions work correctly with:")
|
|
print(" - REAL backend API (localhost:8001)")
|
|
print(" - REAL JWT authentication")
|
|
print(" - REAL company data from Oracle database")
|
|
return True
|
|
else:
|
|
print("\n⚠️ SOME TESTS FAILED")
|
|
print("Please review the errors above")
|
|
return False
|
|
|
|
|
|
if __name__ == "__main__":
|
|
success = asyncio.run(test_real_helpers())
|
|
sys.exit(0 if success else 1)
|