From 8c9a782dfe94525dc5f0893c98fd19543648264b Mon Sep 17 00:00:00 2001 From: historia Date: Tue, 25 Aug 2026 19:03:09 -0400 Subject: fix: tui errors wait for getch() --- app/tests/test_taskview.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'app/tests/test_taskview.py') diff --git a/app/tests/test_taskview.py b/app/tests/test_taskview.py index 4b03b41..6c984ad 100644 --- a/app/tests/test_taskview.py +++ b/app/tests/test_taskview.py @@ -276,6 +276,42 @@ class NoWaitTests(_FakeTui, unittest.TestCase): self.assertNotIn("press any key", text) +class InputModeRestoreTests(_FakeTui, unittest.TestCase): + """run() must leave the screen blocking again when the view exits. + + The views drive their redraw loop with a timed getch; if that cadence + leaked into the hub, single-getch dialogs like tui.flash would dismiss + themselves after one timeout instead of waiting for a key. + """ + + def test_task_view_run_restores_blocking_getch(self): + def fake_worker_main(view): + view._queue.put({"kind": "step_start", "index": 0, + "title": "one"}) + view._queue.put({"kind": "step_done", "index": 0, "rc": 0}) + view._queue.put({"kind": "finish", "phase": "done", "rc": 0}) + + screen = FakeScreen(width=80, height=24) + with patch.object(taskview.TaskView, "_worker_main", + fake_worker_main): + view = taskview.TaskView(screen, "Setup", [_step("one")], + clock=lambda: 1000.0, + wait_on_finish=False) + view._worker = _SyncWorker(view._worker_main) + view.run() + self.assertEqual(screen.timeouts[-1], -1) + + def test_lanes_view_run_restores_blocking_getch(self): + screen = FakeScreen(keys=[27]) # any key leaves the finished view + lanes = [taskview.TaskLane("A", [_step("a")]), + taskview.TaskLane("B", [_step("b")])] + view = taskview.LanesView(screen, "Setup", lanes, + clock=lambda: 1000.0) + with patch.object(taskview.threading, "Thread", _SyncThread): + view.run() + self.assertEqual(screen.timeouts[-1], -1) + + class _SyncWorker: """A stand-in for threading.Thread that runs the target synchronously.""" @@ -286,6 +322,20 @@ class _SyncWorker: self._fn() +class _SyncThread: + """A threading.Thread stand-in that runs its target on start().""" + + def __init__(self, target=None, args=(), kwargs=None, daemon=None): + self._target = target + self._args = args + + def start(self): + self._target(*self._args) + + def join(self, timeout=None): + pass + + class LabelTests(unittest.TestCase): def test_fmt_bytes(self): self.assertEqual(taskview._fmt_bytes(512), "512B") -- cgit v1.2.3