"""The Portfolio page's header, and the holdings table's column chooser. From test users: Refresh prices vanished while prices refreshed; the header read View charts, Refresh prices, Record trade; and a portfolio held only in AUD was offered Avg price (AUD), Cost (AUD), Price (AUD) and Dividends (AUD) twice — a native column and a reporting one, showing the same numbers. """ from __future__ import annotations import re import pytest import factories as fac from test_routes import bind_to_only_portfolio, make_login, session_csrf HTML = {"accept": "text/html"} @pytest.fixture def holding(client, session_factory): """A portfolio holding one AUD instrument.""" make_login(client, session_factory) with session_factory() as s: bind_to_only_portfolio(s) acme = fac.make_instrument(s, "ACME") fac.add_trade(s, acme, "2026-01-05", "buy", 10, "5.00") s.commit() return client def _refresh_button(page: str) -> str: found = re.search(r"", page) assert found, "no Refresh prices button" return found.group(0) def test_refresh_prices_stays_while_prices_refresh(holding, app_module, monkeypatch): monkeypatch.setitem(app_module.feed_status, "running", True) button = _refresh_button(holding.get("/", headers=HTML).text) assert "disabled" in button and 'aria-busy="true"' in button def test_refresh_prices_is_ready_when_nothing_runs(holding, app_module, monkeypatch): monkeypatch.setitem(app_module.feed_status, "running", False) button = _refresh_button(holding.get("/", headers=HTML).text) assert "disabled" not in button and "aria-busy" not in button def test_the_header_reads_quietest_to_loudest(holding): """Refresh prices, Simulate sale, View charts, then the one primary action, last.""" page = holding.get("/", headers=HTML).text head = re.search(r'