Files
roa2web-service-auto/reports-app/telegram-bot/tests/test_formatters.py
Marius Mutu a7a1bef375 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>
2025-10-25 15:09:43 +03:00

366 lines
11 KiB
Python

"""
Unit tests for bot response formatters.
"""
import pytest
from app.bot.formatters import (
format_dashboard_response,
format_invoices_response,
format_treasury_response
)
class TestDashboardFormatter:
"""Tests for dashboard response formatter."""
def test_format_dashboard_basic(self):
"""Test basic dashboard formatting."""
data = {
'sold_total': 150000.50,
'facturi_emise': 45,
'facturi_platite': 30,
'facturi_neplatite': 15,
'total_incasari': 200000.00,
'total_plati': 80000.00
}
company_name = "ACME SRL"
result = format_dashboard_response(data, company_name)
# Check header
assert "📊 **Dashboard Financiar**" in result
# Check sold total
assert "💰 **Sold Total:** 150,000.50 RON" in result
# Check facturi stats
assert "📄 **Facturi:**" in result
assert "Emise: 45" in result
assert "Plătite: 30" in result
assert "Neplătite: 15" in result
# Check cash flow
assert "💵 **Cash Flow:**" in result
assert "Încasări: 200,000.00 RON" in result
assert "Plăți: 80,000.00 RON" in result
assert "Net: 120,000.00 RON" in result
# Check footer
assert "ACME SRL" in result
assert "/selectcompany" in result
def test_format_dashboard_zero_values(self):
"""Test dashboard with zero values."""
data = {
'sold_total': 0,
'facturi_emise': 0,
'facturi_platite': 0,
'facturi_neplatite': 0,
'total_incasari': 0,
'total_plati': 0
}
company_name = "TEST SRL"
result = format_dashboard_response(data, company_name)
assert "0.00 RON" in result
assert "Emise: 0" in result
assert "TEST SRL" in result
def test_format_dashboard_large_numbers(self):
"""Test dashboard with large numbers (millions)."""
data = {
'sold_total': 1234567.89,
'facturi_emise': 999,
'facturi_platite': 500,
'facturi_neplatite': 499,
'total_incasari': 9876543.21,
'total_plati': 5432100.00
}
company_name = "BIG CORP SA"
result = format_dashboard_response(data, company_name)
# Check proper number formatting with commas
assert "1,234,567.89 RON" in result
assert "9,876,543.21 RON" in result
assert "5,432,100.00 RON" in result
def test_format_dashboard_missing_fields(self):
"""Test dashboard with missing fields (defaults to 0)."""
data = {} # Empty data
company_name = "EMPTY SRL"
result = format_dashboard_response(data, company_name)
# Should use defaults (0)
assert "0.00 RON" in result
assert "Emise: 0" in result
class TestInvoicesFormatter:
"""Tests for invoices response formatter."""
def test_format_invoices_basic(self):
"""Test basic invoice list formatting."""
invoices = [
{
'seria': 'FAC',
'numar': '001',
'client': 'Client ABC',
'suma_totala': 5000.00,
'status': 'platit'
},
{
'seria': 'FAC',
'numar': '002',
'client': 'Client XYZ',
'suma_totala': 3500.50,
'status': 'neplatit'
}
]
company_name = "TEST SRL"
result = format_invoices_response(invoices, company_name)
# Check header with count
assert "📄 **Facturi** (2 total)" in result
# Check first invoice
assert "✅ **FAC001**" in result
assert "Client ABC - 5,000.00 RON" in result
assert "Status: platit" in result
# Check second invoice
assert "⏳ **FAC002**" in result
assert "Client XYZ - 3,500.50 RON" in result
assert "Status: neplatit" in result
# Check footer
assert "TEST SRL" in result
def test_format_invoices_empty_list(self):
"""Test with empty invoice list."""
invoices = []
company_name = "EMPTY SRL"
result = format_invoices_response(invoices, company_name)
assert "Nu s-au găsit facturi cu aceste criterii." in result
def test_format_invoices_limit(self):
"""Test invoice list with limit."""
# Create 15 invoices
invoices = [
{
'seria': 'FAC',
'numar': f'{i:03d}',
'client': f'Client {i}',
'suma_totala': 1000 * i,
'status': 'platit'
}
for i in range(1, 16)
]
company_name = "MANY SRL"
result = format_invoices_response(invoices, company_name, limit=10)
# Should show only 10 invoices
assert "**FAC001**" in result
assert "**FAC010**" in result
assert "**FAC011**" not in result # 11th should not appear
# Should show message about remaining
assert "și încă 5 facturi" in result
assert "Folosește filtre" in result
def test_format_invoices_status_emoji(self):
"""Test status emoji selection."""
invoices_platit = [
{'seria': 'A', 'numar': '1', 'client': 'X', 'suma_totala': 100, 'status': 'platit'}
]
invoices_neplatit = [
{'seria': 'B', 'numar': '2', 'client': 'Y', 'suma_totala': 200, 'status': 'neplatit'}
]
result_platit = format_invoices_response(invoices_platit, "TEST")
result_neplatit = format_invoices_response(invoices_neplatit, "TEST")
assert "" in result_platit
assert "" in result_neplatit
def test_format_invoices_missing_fields(self):
"""Test invoices with missing fields."""
invoices = [
{
'seria': '',
'numar': '',
# 'client' missing
# 'suma_totala' missing
# 'status' missing
}
]
company_name = "TEST SRL"
result = format_invoices_response(invoices, company_name)
# Should handle missing fields gracefully
assert "N/A" in result
assert "0.00 RON" in result
class TestTreasuryFormatter:
"""Tests for treasury response formatter."""
def test_format_treasury_basic(self):
"""Test basic treasury formatting."""
data = {
'cash_balance': 50000.00,
'bank_accounts': [
{'banca': 'BCR', 'sold': 100000.00},
{'banca': 'BRD', 'sold': 75000.50}
],
'incoming_payments': 25000.00,
'outgoing_payments': 15000.00
}
company_name = "TREASURY SRL"
result = format_treasury_response(data, company_name)
# Check header
assert "💰 **Trezorerie**" in result
# Check cash balance
assert "💵 **Sold Cash:** 50,000.00 RON" in result
# Check bank accounts
assert "🏦 **Conturi Bancare:** 2" in result
assert "BCR: 100,000.00 RON" in result
assert "BRD: 75,000.50 RON" in result
# Check payments
assert "📊 **Plăți Programate:**" in result
assert "De încasat: 25,000.00 RON" in result
assert "De plătit: 15,000.00 RON" in result
# Check footer
assert "TREASURY SRL" in result
def test_format_treasury_no_bank_accounts(self):
"""Test treasury without bank accounts."""
data = {
'cash_balance': 10000.00,
'incoming_payments': 5000.00,
'outgoing_payments': 3000.00
}
company_name = "CASH ONLY SRL"
result = format_treasury_response(data, company_name)
# Bank accounts section should not appear
assert "🏦 **Conturi Bancare:**" not in result
# Other sections should be present
assert "💵 **Sold Cash:**" in result
assert "📊 **Plăți Programate:**" in result
def test_format_treasury_many_bank_accounts(self):
"""Test treasury with many bank accounts (max 5 shown)."""
data = {
'cash_balance': 0,
'bank_accounts': [
{'banca': f'Banca {i}', 'sold': i * 1000}
for i in range(1, 11) # 10 accounts
],
'incoming_payments': 0,
'outgoing_payments': 0
}
company_name = "MANY BANKS SRL"
result = format_treasury_response(data, company_name)
# Should show 10 in count
assert "🏦 **Conturi Bancare:** 10" in result
# But only first 5 in list
assert "Banca 1:" in result
assert "Banca 5:" in result
assert "Banca 6:" not in result
def test_format_treasury_zero_values(self):
"""Test treasury with zero values."""
data = {
'cash_balance': 0,
'incoming_payments': 0,
'outgoing_payments': 0
}
company_name = "ZERO SRL"
result = format_treasury_response(data, company_name)
assert "0.00 RON" in result
def test_format_treasury_large_numbers(self):
"""Test treasury with large numbers."""
data = {
'cash_balance': 9876543.21,
'bank_accounts': [
{'banca': 'BIG BANK', 'sold': 12345678.90}
],
'incoming_payments': 5555555.55,
'outgoing_payments': 3333333.33
}
company_name = "BIG MONEY SA"
result = format_treasury_response(data, company_name)
# Check proper number formatting
assert "9,876,543.21 RON" in result
assert "12,345,678.90 RON" in result
assert "5,555,555.55 RON" in result
assert "3,333,333.33 RON" in result
class TestFormatterIntegration:
"""Integration tests for formatters."""
def test_all_formatters_have_footer(self):
"""Ensure all formatters include company context footer."""
company = "INTEGRATION TEST SRL"
# Dashboard
dash_result = format_dashboard_response({}, company)
assert company in dash_result
assert "/selectcompany" in dash_result
# Invoices (non-empty)
inv_result = format_invoices_response([
{'seria': 'A', 'numar': '1', 'client': 'X', 'suma_totala': 100, 'status': 'platit'}
], company)
assert company in inv_result
assert "/selectcompany" in inv_result
# Treasury
treas_result = format_treasury_response({}, company)
assert company in treas_result
assert "/selectcompany" in treas_result
def test_number_formatting_consistency(self):
"""Test that all formatters use consistent number formatting."""
test_amount = 1234567.89
# Dashboard
dash_data = {'sold_total': test_amount}
dash_result = format_dashboard_response(dash_data, "TEST")
assert "1,234,567.89" in dash_result
# Invoices
inv_data = [{'seria': 'A', 'numar': '1', 'client': 'X', 'suma_totala': test_amount, 'status': 'platit'}]
inv_result = format_invoices_response(inv_data, "TEST")
assert "1,234,567.89" in inv_result
# Treasury
treas_data = {'cash_balance': test_amount}
treas_result = format_treasury_response(treas_data, "TEST")
assert "1,234,567.89" in treas_result