"""The DCA Schedule page's shape.
This page is what its name says: a **schedule** you follow, with
the plan that generates it behind a button. Two sections went — "Up next" and
"History" — because the calendar already showed both, and the only things they
carried that the calendar cannot (Record buy, Skip) moved onto the row they act
on.
These tests pin that arrangement, because it is the part a later edit undoes
without noticing.
"""
from __future__ import annotations
import re
from freezegun import freeze_time
import factories as fac
from test_routes import make_login
HTML = {"accept": "text/html"}
TODAY = "2026-08-08"
def _plan(client, session_factory, *, tickers="ALPHA", amount="500"):
make_login(client, session_factory)
with session_factory() as s:
fac.hold(s, fac.make_instrument(s, "ALPHA"))
s.commit()
token = re.search(
r'name="_csrf" value="([^"]+)"', client.get("/schedule", headers=HTML).text).group(1)
client.post("/schedule/save",
data={"_csrf": token, "name": "Regular buys", "interval_days": "28",
"amount": amount, "brokerage": "9.50",
"start_date": "2026-01-05", "tickers": tickers},
headers=HTML, follow_redirects=True)
return client.get("/schedule", headers=HTML).text
@freeze_time(TODAY)
def test_the_page_is_called_the_dca_schedule(client, session_factory):
"""'Plan' on its own said nothing about what the page was for."""
make_login(client, session_factory)
page = client.get("/schedule", headers=HTML).text
assert "DCA Schedule" in page
@freeze_time(TODAY)
def test_the_redundant_sections_are_gone(client, session_factory):
"""Both restated the calendar. If either comes back, so does the argument
for why the calendar is not enough."""
page = _plan(client, session_factory)
assert "
Up next
" not in page
assert "
History
" not in page
@freeze_time(TODAY)
def test_record_buy_and_skip_survived_the_sections_that_held_them(client, session_factory):
"""The one thing that had to be kept when Up next went."""
page = _plan(client, session_factory)
assert "/schedule/complete" in page, "Record buy is gone"
assert 'action="/schedule/skip"' in page, "Skip is gone"
@freeze_time(TODAY)
def test_they_appear_once_not_on_every_row(client, session_factory):
"""The rotation has ONE next step. Offering Record buy on every row implies
you can record the third buy before the first."""
page = _plan(client, session_factory)
assert page.count('action="/schedule/skip"') == 1
@freeze_time(TODAY)
def test_the_calendar_comes_before_coming_up(client, session_factory):
"""65/35, calendar on the left — so in source order the calendar is first.
On a narrow screen that is also the stacking order, which is the reason it
matters beyond aesthetics."""
page = _plan(client, session_factory)
assert page.index('class="calendar"') < page.index("Coming up")
@freeze_time(TODAY)
def test_the_plan_editor_is_a_dialog_holding_the_preview(client, session_factory):
page = _plan(client, session_factory)
found = re.search(r'