Files
TimeTracker/tests/test_api_route_contract.py
T
Dries Peeters ef9b66f5e7 fix(api): align client search, OpenAPI version, and Client construction
Global search referenced Client.company, which is not a column on Client, so client matches failed at runtime. Legacy and v1 search, plus search_clients(), now filter on name, email, description, and contact_person; result descriptions use the same fields. Legacy /api/search returns count: 0 for queries shorter than two characters so responses stay consistent.

OpenAPI info.version is taken from get_version_from_setup(), with a config fallback when the resolved version is unknown. get_version_from_setup() also honors TIMETRACKER_VERSION and APP_VERSION for CI and container builds.

Client.__init__ accepts custom_fields. ClientService no longer passes status= into Client(), which the initializer does not support.

Tests add HTTP route contract checks and OpenAPI version alignment, fix subcontractor search fixtures (Client/Task construction and v1 client fixture naming), and update related API integration tests.
2026-04-15 12:57:01 +02:00

48 lines
1.7 KiB
Python

"""Contract checks: curated HTTP paths exist on the Flask url map; OpenAPI version matches app version."""
import pytest
from werkzeug.exceptions import MethodNotAllowed, NotFound
pytestmark = [pytest.mark.api, pytest.mark.integration]
# Paths exercised by tests after drift cleanup; extend when adding stable API coverage.
CONTRACT_ROUTES = (
("/api/v1/info", "GET"),
("/api/v1/health", "GET"),
("/api/timer/status", "GET"),
("/api/timer/stop", "POST"),
("/api/openapi.json", "GET"),
("/api/analytics/hours-by-day", "GET"),
("/api/analytics/hours-by-project", "GET"),
("/api/tasks/create", "POST"),
("/projects/create", "GET"),
("/api/reports/scheduled", "GET"),
)
def test_contract_routes_registered(app):
"""Each curated path must resolve against the application's url map."""
server_name = app.config.get("SERVER_NAME") or "localhost"
adapter = app.url_map.bind(server_name)
for path, method in CONTRACT_ROUTES:
try:
adapter.match(path, method=method)
except NotFound:
pytest.fail(f"No route registered for {method} {path!r}")
except MethodNotAllowed as exc:
pytest.fail(f"Method not allowed for {method} {path!r}: {exc!s}")
def test_openapi_info_version_matches_app_version(app, client):
"""OpenAPI info.version must follow setup.py / env (same as get_version_from_setup)."""
from app.config.analytics_defaults import get_version_from_setup
expected = get_version_from_setup()
if expected == "unknown":
expected = app.config.get("APP_VERSION", "1.0.0")
response = client.get("/api/openapi.json")
assert response.status_code == 200
data = response.get_json()
assert data.get("info", {}).get("version") == expected