Add missing test files and update .gitignore to allow test files
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>
This commit is contained in:
323
reports-app/telegram-bot/tests/test_helpers_real_simple.py
Normal file
323
reports-app/telegram-bot/tests/test_helpers_real_simple.py
Normal file
@@ -0,0 +1,323 @@
|
||||
"""
|
||||
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)
|
||||
Reference in New Issue
Block a user