Files
fuel_track/tests/test_app.py
T
Mateusz Gruszczyński 5f6e4770c1 api auth
2026-07-13 15:04:24 +02:00

203 lines
8.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from app import create_app
from app.database import initialize_database, migrate_database
from app.services import calculate_costs, invoice_period
from datetime import datetime
def make_app(tmp_path, name):
return create_app({"TESTING": True, "SQLALCHEMY_DATABASE_URI": f"sqlite:///{tmp_path / name}"})
def test_health(tmp_path):
app=make_app(tmp_path, "test.db")
assert app.test_client().get('/health').json=={"status":"ok"}
def test_costs_50_percent_vat():
result=calculate_costs(123,23,50)
assert float(result['net'])==100.0
assert float(result['deductible_vat'])==11.5
assert float(result['final_cost'])==111.5
def test_invoice_period():
assert invoice_period(datetime(2026,7,15),15).endswith('0115')
assert invoice_period(datetime(2026,7,16),15).endswith('16koniec')
def test_admin_settings_ajax_has_working_route(tmp_path):
app=make_app(tmp_path, "admin.db")
client=app.test_client()
client.post('/login',data={'email':'admin@example.com','password':'admin123!'})
response=client.post('/admin',data={'action':'settings','name':'Firma','entity_type':'JDG','vat_rate':'23','vat_deduction_percent':'50','invoice_split_day':'15','invoice_split_enabled':'on','region':'mazowieckie','theme':'darkly'},headers={'X-Requested-With':'XMLHttpRequest'})
assert response.status_code==200
assert response.json['ok'] is True
def test_ure_brand_aggregation(tmp_path):
from app.integrations.ure import aggregate_ure_companies
app=make_app(tmp_path, "ure.db")
with app.app_context():
rows=[{"nazwa":"ORLEN S.A.","nip":"7740001454","regon":"610188201","nazwaStacji":"100","wojewodztwo":"mazowieckie","benzynySilnikowe":True},
{"nazwa":"ORLEN S.A.","nip":"7740001454","regon":"610188201","nazwaStacji":"101","wojewodztwo":"śląskie","olejeNapedowe":True}]
result=aggregate_ure_companies(rows)
assert len(result)==1
assert result[0]["brand_name"]=="ORLEN"
assert result[0]["station_count"]==2
def test_ure_duplicate_dkn_is_merged(tmp_path):
from app.integrations.ure import aggregate_ure_companies
app=make_app(tmp_path, "dup.db")
rows=[
{"dkn":977,"nazwa":"Test Sp. z o.o.","nip":"123","nazwaStacji":"Punkt paliw","infraUlica":"A","infraNrLokalu":"1","infraPoczta":"Miasto","benzynySilnikowe":True},
{"dkn":977,"nazwa":"Test Sp. z o.o.","nip":"123","nazwaStacji":"Punkt paliw i LPG","infraUlica":"A","infraNrLokalu":"1","infraPoczta":"Miasto","gazPlynnyLPG":True},
]
with app.app_context():
result=aggregate_ure_companies(rows)
assert len(result)==1
assert result[0]["station_count"]==1
assert len(result[0]["points"])==1
assert result[0]["points"][0]["has_petrol"] is True
assert result[0]["points"][0]["has_lpg"] is True
def test_company_and_card_forms_use_post(tmp_path):
app=make_app(tmp_path, "forms.db")
client=app.test_client()
client.post('/login',data={'email':'admin@example.com','password':'admin123!'})
html=client.get('/admin/companies').get_data(as_text=True)
assert 'action="/api/companies" method="post"' in html
assert 'action="/api/fuel-cards" method="post"' in html
assert 'Nazwa firmy' in html
assert 'Operator karty' in html
def test_cannot_delete_last_admin(tmp_path):
app=make_app(tmp_path, "delete.db")
client=app.test_client()
client.post('/api/auth/login',data={'email':'admin@example.com','password':'admin123!'})
with app.app_context():
from app.models import User
admin=User.query.filter_by(email='admin@example.com').first()
admin_id=admin.id
response=client.delete(f'/api/users/{admin_id}')
assert response.status_code == 400
assert response.json['ok'] is False
def test_cli_reset_admin_password(tmp_path):
app=make_app(tmp_path, "cli.db")
runner=app.test_cli_runner()
result=runner.invoke(args=['reset-admin-password','--email','admin@example.com','--password','NoweHaslo123!'])
assert result.exit_code == 0
client=app.test_client()
response=client.post('/api/auth/login',data={'email':'admin@example.com','password':'NoweHaslo123!'})
assert response.status_code == 200
def test_html_cache_headers_and_static_versioning(tmp_path):
app=make_app(tmp_path, "cache.db")
client=app.test_client()
response=client.get('/login')
assert response.headers['Cache-Control'] == 'no-store, no-cache, private, must-revalidate'
assert response.headers['Pragma'] == 'no-cache'
assert response.headers['Expires'] == '0'
html=response.get_data(as_text=True)
assert '/static/css/layout.css?v=' in html
assert '/static/js/core.js?v=' in html
def test_css_cache_for_30_days(tmp_path):
app=make_app(tmp_path, "static.db")
response=app.test_client().get('/static/css/layout.css')
assert response.status_code == 200
assert response.headers['Cache-Control'] == 'public, max-age=2592000, immutable'
def test_create_app_initializes_database(tmp_path):
from sqlalchemy import inspect
from app.extensions import db
app = create_app({"TESTING": True, "SQLALCHEMY_DATABASE_URI": f"sqlite:///{tmp_path / 'empty.db'}"})
with app.app_context():
tables = inspect(db.engine).get_table_names()
assert "user" in tables
assert "schema_migration" in tables
def test_migration_runner_creates_registry_without_legacy_migrations(tmp_path):
from sqlalchemy import inspect
from app.extensions import db
app = make_app(tmp_path, "migrations.db")
with app.app_context():
assert migrate_database() == []
assert "schema_migration" in inspect(db.engine).get_table_names()
assert migrate_database() == []
def test_global_vat_override_changes_50_percent_deduction(tmp_path):
from decimal import Decimal
from datetime import date
from app.extensions import db
from app.models import AppSetting
from app.vat import effective_vat_rate
app = make_app(tmp_path, "global-vat.db")
with app.app_context():
for key, value in {
"global_vat_override_enabled": "1",
"global_vat_override_name": "CPN",
"global_vat_override_rate": "8",
"global_vat_override_start": "2026-07-01",
"global_vat_override_end": "2026-07-31",
}.items():
db.session.merge(AppSetting(key=key, value=value))
db.session.commit()
rate = effective_vat_rate(Decimal("23"), date(2026, 7, 15))
result = calculate_costs(Decimal("108"), rate, 50)
assert rate == Decimal("8")
assert result["net"] == Decimal("100.00")
assert result["vat"] == Decimal("8.00")
assert result["deductible_vat"] == Decimal("4.00")
assert effective_vat_rate(Decimal("23"), date(2026, 8, 1)) == Decimal("23")
def test_only_admin_can_change_global_vat(tmp_path):
app = make_app(tmp_path, "global-vat-auth.db")
client = app.test_client()
client.post('/login', data={'email':'admin@example.com','password':'admin123!'})
response = client.post('/admin/global-vat', data={'enabled':'on','name':'CPN','rate':'8','start':'2026-07-01','end':'2026-07-31'}, headers={'X-Requested-With':'XMLHttpRequest'})
assert response.status_code == 200
assert response.json['ok'] is True
def test_api_bearer_token_authentication(tmp_path):
app = make_app(tmp_path, "bearer.db")
client = app.test_client()
token_response = client.post('/api/auth/token', data={
'username': 'admin@example.com',
'password': 'admin123!',
})
assert token_response.status_code == 200
token = token_response.json['access_token']
assert token_response.json['token_type'] == 'Bearer'
fresh_client = app.test_client()
response = fresh_client.get('/api/me', headers={
'Authorization': f'Bearer {token}',
})
assert response.status_code == 200
assert response.json['data']['email'] == 'admin@example.com'
def test_api_rejects_invalid_bearer_token(tmp_path):
app = make_app(tmp_path, "invalid-bearer.db")
response = app.test_client().get('/api/me', headers={
'Authorization': 'Bearer invalid-token',
})
assert response.status_code == 401
assert response.json['ok'] is False
def test_openapi_contains_password_flow(tmp_path):
app = make_app(tmp_path, "openapi-auth.db")
spec = app.test_client().get('/openapi.json').json
password_flow = spec['components']['securitySchemes']['oauth2Password']['flows']['password']
assert password_flow['tokenUrl'] == '/api/auth/token'
assert '/api/auth/token' in spec['paths']