Cover the balance entry path and three unguarded rules
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.
This commit is contained in:
@@ -34,6 +34,7 @@ from dateutil.easter import easter
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from httpx import ASGITransport, AsyncClient
|
||||
|
||||
from app.config import settings
|
||||
from app.dependencies import get_connection
|
||||
from app.main import app
|
||||
from app.utils.holidays import cached_year_bounds
|
||||
@@ -687,6 +688,38 @@ class TestAge4ProjectionArithmeticIsSelfConsistent:
|
||||
async def test_expiring_equals_projected_minus_ceiling_clamped_at_zero(
|
||||
self, client: AsyncClient, connection: aiosqlite.Connection
|
||||
) -> None:
|
||||
"""Independently-derived expected values, not internal consistency.
|
||||
|
||||
The original version of this test re-derived its expected
|
||||
`expiring_at_b4` from `projection["projected_left_at_b4"]` -- a field
|
||||
of the SAME response it was checking -- so it only proved the two
|
||||
response fields agree with each other, not that either is correct
|
||||
(a shared bug in both would still pass; the test's own docstring
|
||||
said as much).
|
||||
|
||||
This version instead computes the expected numbers from the seeded
|
||||
fixture and `settings.rules` directly, independent of the response.
|
||||
The `/api/plan/propose` response's `age4_projections` come from
|
||||
`allocation_service._Ledger._age4_projections`, not from
|
||||
`AnalyticsService.get_days_left_at_age_4` -- that method always
|
||||
passes `days_used=0` and derives `total_initial` from the
|
||||
(parent, child) pool `AllocationInputLoader.load` built
|
||||
(`allocation_service.py:1446-1475`). No wish is created in this
|
||||
test, so nothing gets proposed and `planned_fp_before_b4` is 0.
|
||||
With no `ParentalLeaveFetch` snapshot for this brand-new
|
||||
registration, that pool falls back to `rules.sjukpenning_days // 2 +
|
||||
rules.lagsta_niva_days // 2`, which is `rules.days_per_parent`
|
||||
exactly (the "Bug A" default the two must agree on -- see
|
||||
`test_planning_service_apply.py`'s
|
||||
`test_no_snapshot_default_balance_matches_allocation_engine`) --
|
||||
making `projected_left_at_b4 == rules.days_per_parent`. The
|
||||
workspace is a fresh single-member 'solo' workspace (never set to
|
||||
'couple' here), so the per-CHILD cap
|
||||
(`rules.max_savable_days_at_age_4`) applies via
|
||||
`resolve_age4_savable_cap`, not the per-parent one -- making
|
||||
`expiring_at_b4 == max(rules.days_per_parent -
|
||||
rules.max_savable_days_at_age_4, 0)`.
|
||||
"""
|
||||
headers, ws_id, pd_uuid = await _register(client, "age4-projection@example.com", "Alex")
|
||||
birth_date = date.today() - relativedelta(months=6)
|
||||
child_id = await _add_child(client, headers, ws_id, "Barn", birth_date)
|
||||
@@ -695,11 +728,19 @@ class TestAge4ProjectionArithmeticIsSelfConsistent:
|
||||
|
||||
proposal = await _propose(client, headers, ws_id)
|
||||
|
||||
rules = settings.rules
|
||||
expected_cap = rules.max_savable_days_at_age_4
|
||||
expected_projected_left = rules.days_per_parent
|
||||
expected_expiring = max(expected_projected_left - expected_cap, 0)
|
||||
expected_savable = min(expected_projected_left, expected_cap)
|
||||
|
||||
assert proposal["age4_projections"], "expected an age4 projection for the (parent, child)"
|
||||
for projection in proposal["age4_projections"]:
|
||||
assert projection["child_id"] == str(child_id)
|
||||
expected = max(projection["projected_left_at_b4"] - 96, 0)
|
||||
assert projection["expiring_at_b4"] == expected, projection
|
||||
assert projection["savable_cap_at_b4"] == expected_cap, projection
|
||||
assert projection["projected_left_at_b4"] == expected_projected_left, projection
|
||||
assert projection["expiring_at_b4"] == expected_expiring, projection
|
||||
assert projection["savable_after_b4"] == expected_savable, projection
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user