Files
TimeTracker/tests/test_client_single_simplification.py
T
MacJediWizard 6cbe869fc1 fix(tests, api): four small CI failures from v5.5.6 test-fixture tightening
Bundles four narrow fixes surfaced by the comprehensive CI run after
v5.5.6 enabled SQLite FK enforcement and refreshed test fixtures. Each
fix is independent; bundled here only to keep PR overhead low.

1. tests/test_routes/test_api_v1_expenses_complete.py
   - Add missing `User` import. `test_expense_permissions` references
     `User.query.filter(...)` but `User` was never imported, causing a
     NameError at test runtime.

2. tests/test_client_single_simplification.py
   - `Client(...status="active")` failed with TypeError because the
     Client model's __init__ does not accept `status` as a keyword
     (column default already sets it to "active"). Set the attribute
     after construction.

3. tests/test_utils/test_api_auth_enhanced.py
   - `User(username=..., is_active=True)` failed because User.__init__
     does not accept `is_active`. Set the attribute after construction.
   - 9 occurrences of `app.test_request_context(remote_addr="...")`
     failed with `TypeError: EnvironBuilder.__init__() got an unexpected
     keyword argument 'remote_addr'`. Werkzeug removed the keyword;
     replace with `environ_overrides={"REMOTE_ADDR": "..."}` which is
     the supported equivalent.

4. app/routes/api_v1_time_entries.py
   - DELETE /api/v1/time-entries/<id> returned 415 Unsupported Media
     Type when called without an `application/json` Content-Type, even
     though the body is optional (only used to capture an audit reason).
     Switch to `request.get_json(silent=True)` so the endpoint accepts
     DELETE requests with no body. Same change applied to no other
     methods; POST/PUT continue to require explicit JSON.

The route file also picked up a black/isort pass from the project
auto-formatter; behaviour is identical to before, only whitespace and
import grouping differ.

Test plan
- pytest tests/test_routes/test_api_v1_expenses_complete.py::TestAPIExpensesComplete::test_expense_permissions
- pytest tests/test_client_single_simplification.py::test_manual_entry_shows_select_when_multiple_clients
- pytest tests/test_utils/test_api_auth_enhanced.py::TestAuthenticateToken
- pytest tests/test_routes/test_api_v1_time_entries_complete.py::TestAPITimeEntriesComplete::test_delete_time_entry_uses_service_layer
2026-05-14 16:44:06 -04:00

65 lines
2.3 KiB
Python

"""
Tests for Client Single-Client Simplification (Issue #467).
When only one active client exists, the client selection field is pre-filled
and grayed out across manual time logging, project creation, and similar forms.
"""
import pytest
from app import db
from app.models import Client
from flask import url_for
@pytest.mark.integration
@pytest.mark.routes
def test_manual_entry_shows_single_client_prefilled(
authenticated_client, app, user, test_client
):
"""When only one client exists, manual entry form shows pre-filled grayed-out client."""
with app.app_context():
# Ensure exactly one active client (test_client from fixture)
active_count = Client.query.filter_by(status="active").count()
assert active_count == 1, "Expected exactly 1 active client for this test"
response = authenticated_client.get(url_for("timer.manual_entry"))
assert response.status_code == 200
html = response.get_data(as_text=True)
# Should have hidden input for client_id (single-client mode)
assert 'name="client_id"' in html
assert f'value="{test_client.id}"' in html
# Should have disabled readonly display
assert "disabled" in html
assert "readonly" in html
assert test_client.name in html
@pytest.mark.integration
@pytest.mark.routes
def test_manual_entry_shows_select_when_multiple_clients(
authenticated_client, app, user, test_client
):
"""When multiple clients exist, manual entry form shows normal client select."""
with app.app_context():
# Add a second client
second = Client(
name="Second Client",
email="second@example.com",
)
second.status = "active"
db.session.add(second)
db.session.commit()
active_count = Client.query.filter_by(status="active").count()
assert active_count >= 2
response = authenticated_client.get(url_for("timer.manual_entry"))
assert response.status_code == 200
html = response.get_data(as_text=True)
# Should have normal select, not single-client hidden + disabled
assert "<select" in html
assert 'id="client_id"' in html or 'name="client_id"' in html
assert "Select a client" in html or "client" in html.lower()