mirror of
https://github.com/DRYTRIX/TimeTracker.git
synced 2026-02-16 10:38:45 -06:00
395 lines
12 KiB
Python
395 lines
12 KiB
Python
"""
|
|
Test suite for currency display functionality.
|
|
|
|
This test ensures that all Finance pages (Reports, Payments, Expenses)
|
|
properly respect the currency setting from the database/environment
|
|
instead of hardcoding Euro symbols.
|
|
"""
|
|
|
|
import pytest
|
|
from datetime import datetime, date, timedelta
|
|
from decimal import Decimal
|
|
from app import db
|
|
from app.models import User, Project, Settings, Client, Payment, Invoice, Expense
|
|
from flask_login import login_user
|
|
|
|
|
|
@pytest.fixture
|
|
def admin_user(app):
|
|
"""Create an admin user for testing."""
|
|
user = User(username='admin', role='admin')
|
|
user.is_active = True # Set after creation
|
|
user.set_password('test123')
|
|
db.session.add(user)
|
|
db.session.commit()
|
|
return user
|
|
|
|
|
|
@pytest.fixture
|
|
def test_client_with_auth(app, client, admin_user):
|
|
"""Return authenticated client."""
|
|
with client.session_transaction() as sess:
|
|
sess['_user_id'] = str(admin_user.id)
|
|
return client
|
|
|
|
|
|
@pytest.fixture
|
|
def usd_settings(app):
|
|
"""Set currency to USD for testing."""
|
|
settings = Settings.get_settings()
|
|
settings.currency = 'USD'
|
|
db.session.commit()
|
|
return settings
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_client(app):
|
|
"""Create a sample client."""
|
|
client = Client(
|
|
name='Test Client',
|
|
email='test@example.com'
|
|
)
|
|
db.session.add(client)
|
|
db.session.commit()
|
|
return client
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_project(app, sample_client):
|
|
"""Create a sample project."""
|
|
project = Project(
|
|
name='Test Project',
|
|
client_id=sample_client.id,
|
|
status='active',
|
|
hourly_rate=Decimal('100.00')
|
|
)
|
|
db.session.add(project)
|
|
db.session.commit()
|
|
return project
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_invoice(app, sample_project, admin_user, sample_client):
|
|
"""Create a sample invoice."""
|
|
invoice = Invoice(
|
|
invoice_number='INV-TEST-001',
|
|
project_id=sample_project.id,
|
|
client_name=sample_client.name,
|
|
due_date=date.today() + timedelta(days=30),
|
|
created_by=admin_user.id,
|
|
client_id=sample_client.id,
|
|
status='sent',
|
|
currency_code='USD'
|
|
)
|
|
db.session.add(invoice)
|
|
db.session.commit()
|
|
return invoice
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_payment(app, sample_invoice):
|
|
"""Create a sample payment."""
|
|
payment = Payment(
|
|
invoice_id=sample_invoice.id,
|
|
amount=Decimal('1000.00'),
|
|
currency='USD',
|
|
payment_date=date.today(),
|
|
method='bank_transfer',
|
|
status='completed',
|
|
gateway_fee=Decimal('10.00')
|
|
)
|
|
db.session.add(payment)
|
|
db.session.commit()
|
|
return payment
|
|
|
|
|
|
@pytest.fixture
|
|
def sample_expense(app, admin_user, sample_project):
|
|
"""Create a sample expense."""
|
|
expense = Expense(
|
|
user_id=admin_user.id,
|
|
title='Test Expense',
|
|
category='travel',
|
|
amount=Decimal('250.00'),
|
|
expense_date=date.today(),
|
|
project_id=sample_project.id,
|
|
currency_code='USD',
|
|
status='approved'
|
|
)
|
|
db.session.add(expense)
|
|
db.session.commit()
|
|
return expense
|
|
|
|
|
|
# Unit tests for template filters
|
|
@pytest.mark.unit
|
|
@pytest.mark.templates
|
|
def test_currency_symbol_filter_usd(app):
|
|
"""Test currency_symbol filter returns correct symbol for USD."""
|
|
with app.app_context():
|
|
from app.utils.template_filters import register_template_filters
|
|
register_template_filters(app)
|
|
|
|
# Test USD
|
|
result = app.jinja_env.filters['currency_symbol']('USD')
|
|
assert result == '$'
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.templates
|
|
def test_currency_symbol_filter_eur(app):
|
|
"""Test currency_symbol filter returns correct symbol for EUR."""
|
|
with app.app_context():
|
|
from app.utils.template_filters import register_template_filters
|
|
register_template_filters(app)
|
|
|
|
# Test EUR
|
|
result = app.jinja_env.filters['currency_symbol']('EUR')
|
|
assert result == '€'
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.templates
|
|
def test_currency_symbol_filter_gbp(app):
|
|
"""Test currency_symbol filter returns correct symbol for GBP."""
|
|
with app.app_context():
|
|
from app.utils.template_filters import register_template_filters
|
|
register_template_filters(app)
|
|
|
|
# Test GBP
|
|
result = app.jinja_env.filters['currency_symbol']('GBP')
|
|
assert result == '£'
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.templates
|
|
def test_currency_symbol_filter_fallback(app):
|
|
"""Test currency_symbol filter returns currency code for unknown currencies."""
|
|
with app.app_context():
|
|
from app.utils.template_filters import register_template_filters
|
|
register_template_filters(app)
|
|
|
|
# Test unknown currency
|
|
result = app.jinja_env.filters['currency_symbol']('XYZ')
|
|
assert result == 'XYZ'
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.templates
|
|
def test_currency_icon_filter_usd(app):
|
|
"""Test currency_icon filter returns correct icon for USD."""
|
|
with app.app_context():
|
|
from app.utils.template_filters import register_template_filters
|
|
register_template_filters(app)
|
|
|
|
# Test USD
|
|
result = app.jinja_env.filters['currency_icon']('USD')
|
|
assert result == 'fa-dollar-sign'
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.templates
|
|
def test_currency_icon_filter_eur(app):
|
|
"""Test currency_icon filter returns correct icon for EUR."""
|
|
with app.app_context():
|
|
from app.utils.template_filters import register_template_filters
|
|
register_template_filters(app)
|
|
|
|
# Test EUR
|
|
result = app.jinja_env.filters['currency_icon']('EUR')
|
|
assert result == 'fa-euro-sign'
|
|
|
|
|
|
# Integration tests for context processor
|
|
@pytest.mark.integration
|
|
@pytest.mark.templates
|
|
def test_currency_injected_in_template_context(app, usd_settings):
|
|
"""Test that currency is properly injected into template context."""
|
|
with app.test_request_context():
|
|
from app.utils.context_processors import register_context_processors
|
|
register_context_processors(app)
|
|
|
|
# Simulate a request and get the injected context
|
|
with app.app_context():
|
|
context = app.jinja_env.globals
|
|
# Currency should be available
|
|
assert 'currency' in context or usd_settings.currency == 'USD'
|
|
|
|
|
|
# Smoke tests for finance pages
|
|
@pytest.mark.smoke
|
|
@pytest.mark.routes
|
|
def test_reports_page_displays_usd(test_client_with_auth, admin_user, usd_settings, sample_payment):
|
|
"""Test that Reports page displays USD symbol instead of hardcoded Euro."""
|
|
# Access reports page
|
|
response = test_client_with_auth.get('/reports')
|
|
assert response.status_code == 200
|
|
|
|
# Check that USD symbol is present
|
|
data = response.data.decode('utf-8')
|
|
|
|
# The page should NOT contain hardcoded Euro symbols
|
|
# (Note: We allow € in the currency dropdown/selector if it exists)
|
|
# Check that USD formatting is used in the summary cards
|
|
assert '$' in data or 'currency' in data.lower()
|
|
|
|
# If we have actual payment data, check it's formatted correctly
|
|
if sample_payment:
|
|
# Should have dollar amounts
|
|
assert '1000.00' in data or '1,000.00' in data
|
|
|
|
|
|
@pytest.mark.smoke
|
|
@pytest.mark.routes
|
|
def test_payments_page_displays_usd(test_client_with_auth, admin_user, usd_settings, sample_payment):
|
|
"""Test that Payments list page displays USD symbol instead of hardcoded Euro."""
|
|
# Access payments page
|
|
response = test_client_with_auth.get('/payments')
|
|
assert response.status_code == 200
|
|
|
|
data = response.data.decode('utf-8')
|
|
|
|
# Check that currency info is present
|
|
assert '$' in data or 'USD' in data or 'currency' in data.lower()
|
|
|
|
# Should display payment amounts
|
|
assert '1000.00' in data or '1,000.00' in data
|
|
|
|
|
|
@pytest.mark.smoke
|
|
@pytest.mark.routes
|
|
def test_expenses_list_page_displays_usd(test_client_with_auth, admin_user, usd_settings, sample_expense):
|
|
"""Test that Expenses list page displays USD symbol instead of hardcoded Euro."""
|
|
# Access expenses page
|
|
response = test_client_with_auth.get('/expenses')
|
|
assert response.status_code == 200
|
|
|
|
data = response.data.decode('utf-8')
|
|
|
|
# Check that currency info is present
|
|
assert '$' in data or 'USD' in data or 'currency' in data.lower()
|
|
|
|
# Should display expense amounts
|
|
assert '250.00' in data
|
|
|
|
|
|
@pytest.mark.smoke
|
|
@pytest.mark.routes
|
|
def test_expenses_dashboard_displays_usd(test_client_with_auth, admin_user, usd_settings, sample_expense):
|
|
"""Test that Expenses dashboard displays USD symbol instead of hardcoded Euro."""
|
|
# Access expenses dashboard
|
|
response = test_client_with_auth.get('/expenses/dashboard')
|
|
assert response.status_code == 200
|
|
|
|
data = response.data.decode('utf-8')
|
|
|
|
# Check that currency info is present
|
|
assert '$' in data or 'USD' in data or 'currency' in data.lower()
|
|
|
|
# Should display expense amounts
|
|
assert '250.00' in data
|
|
|
|
|
|
# Model tests
|
|
@pytest.mark.unit
|
|
@pytest.mark.models
|
|
def test_settings_default_currency(app):
|
|
"""Test that Settings model has correct default currency from config."""
|
|
with app.app_context():
|
|
from app.config import Config
|
|
settings = Settings.get_settings()
|
|
|
|
# Should match the Config default (which can be EUR or USD depending on env)
|
|
assert settings.currency in ['EUR', 'USD', 'GBP', 'JPY']
|
|
assert len(settings.currency) == 3
|
|
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.models
|
|
def test_settings_currency_can_be_changed(app):
|
|
"""Test that currency setting can be changed."""
|
|
with app.app_context():
|
|
settings = Settings.get_settings()
|
|
original_currency = settings.currency
|
|
|
|
# Change to USD
|
|
settings.currency = 'USD'
|
|
db.session.commit()
|
|
|
|
# Verify change
|
|
db.session.expire(settings)
|
|
db.session.refresh(settings)
|
|
assert settings.currency == 'USD'
|
|
|
|
# Change back
|
|
settings.currency = original_currency
|
|
db.session.commit()
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.templates
|
|
def test_currency_consistency_across_pages(test_client_with_auth, admin_user, usd_settings,
|
|
sample_payment, sample_expense):
|
|
"""Test that currency is consistent across all finance pages."""
|
|
pages_to_check = [
|
|
'/reports',
|
|
'/payments',
|
|
'/expenses',
|
|
'/expenses/dashboard'
|
|
]
|
|
|
|
for page_url in pages_to_check:
|
|
response = test_client_with_auth.get(page_url)
|
|
assert response.status_code == 200, f"Failed to load {page_url}"
|
|
|
|
data = response.data.decode('utf-8')
|
|
|
|
# Each page should have currency indicators
|
|
# We're checking for either $ (USD symbol) or USD text or generic currency text
|
|
has_currency = '$' in data or 'USD' in data or 'currency' in data.lower()
|
|
assert has_currency, f"No currency indicator found on {page_url}"
|
|
|
|
|
|
@pytest.mark.integration
|
|
@pytest.mark.routes
|
|
def test_payments_with_different_currencies(app, test_client_with_auth, admin_user,
|
|
sample_invoice):
|
|
"""Test that payments with different currencies are displayed correctly."""
|
|
with app.app_context():
|
|
# Create payments with different currencies
|
|
payment_usd = Payment(
|
|
invoice_id=sample_invoice.id,
|
|
amount=Decimal('1000.00'),
|
|
currency='USD',
|
|
payment_date=date.today(),
|
|
method='bank_transfer',
|
|
status='completed'
|
|
)
|
|
|
|
payment_eur = Payment(
|
|
invoice_id=sample_invoice.id,
|
|
amount=Decimal('850.00'),
|
|
currency='EUR',
|
|
payment_date=date.today(),
|
|
method='stripe',
|
|
status='completed'
|
|
)
|
|
|
|
db.session.add_all([payment_usd, payment_eur])
|
|
db.session.commit()
|
|
|
|
# Access payments page
|
|
response = test_client_with_auth.get('/payments')
|
|
assert response.status_code == 200
|
|
|
|
data = response.data.decode('utf-8')
|
|
|
|
# Both currencies should be displayed
|
|
assert 'USD' in data
|
|
assert 'EUR' in data
|
|
|
|
|
|
if __name__ == '__main__':
|
|
pytest.main([__file__, '-v'])
|
|
|