0fc71101ae
Entering a parent's Försäkringskassan balances had no tests at all, despite being how every number in the planner originates and despite it becoming the first thing a new user does. The scraper endpoints are pinned per test rather than read from the ambient configuration, because a local .env sets the flag opposite to the shipped default and a test that trusts it would pass here and fail in CI. Also covered: the hard expiry at twelve, whose rejection path nothing reached and whose boundary turns out to be inclusive; and the dubbeldagar count cap, which now drives past the limit and asserts the days beyond it fall back to a single parent. Two weak assertions were strengthened, including one that derived its expectation from the same response it was checking and so could not have failed on a shared error.
164 lines
6.0 KiB
Python
164 lines
6.0 KiB
Python
"""Tests for `ManualFetchService` (backend/app/services/fetch_data_service.py).
|
|
|
|
This is the manual-entry path a parent's Försäkringskassan balances enter the
|
|
app through — now the primary onboarding action. `git grep` found zero
|
|
existing coverage for this service or its router before this file.
|
|
|
|
`test_fk_scraper.py::test_reserved_days_derived` already proves the
|
|
`reserved_days_left <= reserved_days_total` domain rule holds for the
|
|
scraper-side derivation; this file proves the equivalent manual-entry
|
|
boundary — the `ManualFetchService.save_manual_entry` validation itself —
|
|
which was previously untested.
|
|
"""
|
|
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
|
|
from app.repositories_impl.sqlite.parental_leave_repository import SQLiteParentalLeaveRepository
|
|
from app.services.fetch_data_service import ManualFetchService
|
|
from app.utils.errors import ValidationError
|
|
from tests.conftest import SeededIds
|
|
|
|
|
|
def _valid_kwargs(seeded_ids: SeededIds, **overrides: object) -> dict:
|
|
base = dict(
|
|
personal_data_uuid=seeded_ids.personal_data_uuid,
|
|
workspace_id=seeded_ids.workspace_id,
|
|
child_id=seeded_ids.child_id,
|
|
total_days=480,
|
|
days_used=100,
|
|
reserved_days_total=90,
|
|
reserved_days_left=90,
|
|
transferable_days_left=150,
|
|
dubbeldagar_left=60,
|
|
sjukpenning_total=390,
|
|
sjukpenning_used=80,
|
|
lagsta_niva_total=90,
|
|
lagsta_niva_used=20,
|
|
)
|
|
base.update(overrides)
|
|
return base
|
|
|
|
|
|
@pytest.fixture
|
|
def manual_fetch_service(
|
|
parental_leave_repo: SQLiteParentalLeaveRepository,
|
|
) -> ManualFetchService:
|
|
return ManualFetchService(parental_leave_repo)
|
|
|
|
|
|
class TestSaveManualEntryValidation:
|
|
async def test_days_used_exceeding_total_days_is_rejected(
|
|
self,
|
|
manual_fetch_service: ManualFetchService,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
kwargs = _valid_kwargs(seeded_ids, total_days=100, days_used=101)
|
|
with pytest.raises(ValidationError, match="days_used cannot exceed total_days"):
|
|
await manual_fetch_service.save_manual_entry(**kwargs)
|
|
|
|
async def test_days_used_equal_to_total_days_is_accepted(
|
|
self,
|
|
manual_fetch_service: ManualFetchService,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
"""The boundary itself (0 days left) is valid, not an off-by-one reject."""
|
|
kwargs = _valid_kwargs(seeded_ids, total_days=100, days_used=100)
|
|
fetch = await manual_fetch_service.save_manual_entry(**kwargs)
|
|
assert fetch.days_left == 0
|
|
|
|
async def test_reserved_days_left_exceeding_total_is_rejected(
|
|
self,
|
|
manual_fetch_service: ManualFetchService,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
kwargs = _valid_kwargs(seeded_ids, reserved_days_total=90, reserved_days_left=91)
|
|
with pytest.raises(
|
|
ValidationError, match="reserved_days_left cannot exceed reserved_days_total"
|
|
):
|
|
await manual_fetch_service.save_manual_entry(**kwargs)
|
|
|
|
async def test_reserved_days_left_equal_to_total_is_accepted(
|
|
self,
|
|
manual_fetch_service: ManualFetchService,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
kwargs = _valid_kwargs(seeded_ids, reserved_days_total=90, reserved_days_left=90)
|
|
fetch = await manual_fetch_service.save_manual_entry(**kwargs)
|
|
assert fetch.reserved_days_left == 90
|
|
|
|
async def test_valid_payload_is_accepted_and_derived_fields_are_correct(
|
|
self,
|
|
manual_fetch_service: ManualFetchService,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
kwargs = _valid_kwargs(
|
|
seeded_ids,
|
|
total_days=480,
|
|
days_used=100,
|
|
sjukpenning_total=390,
|
|
sjukpenning_used=80,
|
|
lagsta_niva_total=90,
|
|
lagsta_niva_used=20,
|
|
)
|
|
fetch = await manual_fetch_service.save_manual_entry(**kwargs)
|
|
|
|
assert fetch.source == "manual"
|
|
assert fetch.days_left == 380
|
|
assert fetch.tier_data.sjukpenning_left == 310
|
|
assert fetch.tier_data.lagsta_niva_left == 70
|
|
assert fetch.id is not None
|
|
assert fetch.created_at is not None
|
|
assert fetch.updated_at is not None
|
|
|
|
|
|
class TestSaveManualEntryPersistence:
|
|
async def test_snapshot_persists_and_is_readable_via_get_latest(
|
|
self,
|
|
manual_fetch_service: ManualFetchService,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
kwargs = _valid_kwargs(seeded_ids)
|
|
saved = await manual_fetch_service.save_manual_entry(**kwargs)
|
|
|
|
latest = await manual_fetch_service.get_latest(
|
|
seeded_ids.personal_data_uuid, seeded_ids.child_id
|
|
)
|
|
assert latest is not None
|
|
assert latest.id == saved.id
|
|
assert latest.total_days == saved.total_days
|
|
assert latest.tier_data.sjukpenning_left == saved.tier_data.sjukpenning_left
|
|
|
|
async def test_get_latest_with_no_snapshot_returns_none(
|
|
self,
|
|
manual_fetch_service: ManualFetchService,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
result = await manual_fetch_service.get_latest(uuid4(), uuid4())
|
|
assert result is None
|
|
|
|
async def test_list_history_returns_all_snapshots_newest_first(
|
|
self,
|
|
manual_fetch_service: ManualFetchService,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
await manual_fetch_service.save_manual_entry(**_valid_kwargs(seeded_ids, days_used=50))
|
|
await manual_fetch_service.save_manual_entry(**_valid_kwargs(seeded_ids, days_used=60))
|
|
await manual_fetch_service.save_manual_entry(**_valid_kwargs(seeded_ids, days_used=70))
|
|
|
|
history = await manual_fetch_service.list_history(
|
|
seeded_ids.personal_data_uuid, seeded_ids.child_id
|
|
)
|
|
|
|
assert len(history) == 3
|
|
assert [h.days_used for h in history] == [70, 60, 50]
|
|
|
|
async def test_list_history_with_no_snapshots_returns_empty_list(
|
|
self,
|
|
manual_fetch_service: ManualFetchService,
|
|
seeded_ids: SeededIds,
|
|
) -> None:
|
|
history = await manual_fetch_service.list_history(uuid4(), uuid4())
|
|
assert history == []
|