"""The Portfolio table's column order, dragged in a real browser. Drag is layered over the arrow buttons: it moves the list items and rewrites what they carry, and the form posts the same either way. Its tests read the markup, and none had dragged anything. So a seeded walk drags columns about and, after every drop, holds the list to a plain list kept beside it: the order shown, the order the form will post, the positions shown, and which arrows can still move anything. The positions were left behind: after a drag the numbers stayed where they started, so the list read 3, 1, 2 down the page. The numbers exist because a two-column grid of names does not say whether it reads across or down. """ from __future__ import annotations import json import re import subprocess import pytest from test_trade_dialog_in_the_browser import CHROME, HTML, _standalone import factories as fac from test_routes import bind_to_only_portfolio, make_login pytestmark = pytest.mark.visual WALK = """ """ @pytest.mark.parametrize("seed", [1, 2, 3]) def test_dragging_columns_keeps_every_part_of_the_list_in_step(client, session_factory, tmp_path, seed): make_login(client, session_factory) with session_factory() as s: bind_to_only_portfolio(s) fac.add_trade(s, fac.make_instrument(s, "ACME"), "2026-01-05", "buy", 10, "5.00") s.commit() page = client.get("/", headers=HTML) assert page.status_code == 200 target = tmp_path / "dashboard.html" target.write_text(_standalone(page.text, WALK.replace("SEED", str(seed))), encoding="utf-8") dom = subprocess.run( [CHROME, "--headless", "--disable-gpu", "--dump-dom", "--no-sandbox", "--allow-file-access-from-files", "--window-size=1400,1000", "--virtual-time-budget=5000", target.as_uri()], capture_output=True, text=True, timeout=90).stdout found = re.search(r'
(.*?)', dom, re.S) assert found, "the walk did not finish" out = json.loads(found.group(1).replace(""", '"')) assert out["columns"] >= 3 and out["drops"] >= 5, out # the walk did walk assert out["problems"] == [], out["problems"]