aboutsummaryrefslogtreecommitdiffstats
path: root/tests/_fixtures.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/_fixtures.py')
-rw-r--r--tests/_fixtures.py51
1 files changed, 51 insertions, 0 deletions
diff --git a/tests/_fixtures.py b/tests/_fixtures.py
index 0b72856..16192fa 100644
--- a/tests/_fixtures.py
+++ b/tests/_fixtures.py
@@ -22,12 +22,63 @@ doesn't silently test the previous one. `.pristine.i64` is gitignored.
"""
from __future__ import annotations
+import asyncio
import contextlib
import os
import shutil
import tempfile
+def fast_keys() -> None:
+ """Make a simulated keypress cost ~2ms instead of ~85ms. Call before the app.
+
+ **The problem.** Textual sends a key and then calls ``wait_for_idle``
+ *twice*, and that helper sleeps in 20ms granules until *process* time stops
+ advancing -- a CPU-load heuristic standing in for "the state is predictable
+ now", which takes even more granules on a loaded box. Measured here: 84ms
+ per keypress, which was 23s of the pilot suite's 43s.
+
+ **The fix, and why it is not just deletion.** Removing the heuristic alone
+ broke nine checks that read state straight after a keypress -- so it *was*
+ doing a job, badly. This replaces it with the real gate the rest of the
+ suite already uses: send the keys, then ``settle`` (message pump drained,
+ threaded workers finished). That is strictly stronger than "the CPU looks
+ idle", and it is ~2ms.
+
+ **What it still cannot see:** anything driven by a TIMER rather than a
+ worker -- the function-list filter's 80ms debounce, and Textual's own frame
+ timer (so a widget's ``region``/``size`` is not laid out just because the
+ app settled). Those need a wait on the effect: ``wait(lambda: rows < full)``,
+ ``wait(lambda: inp.region.height >= 1)``. Every such site in this repo is
+ commented; if a check that reads geometry or a debounced view starts
+ flaking, that is the reason.
+
+ Verified equivalent, not just faster: pressing j 40 times moves 40 rows with
+ and without the patch, and the full suite passes with identical counts.
+ """
+ import textual.app
+ from textual.pilot import Pilot
+
+ from idatui._sync import settle
+
+ if not hasattr(textual.app, "wait_for_idle"): # pragma: no cover
+ raise RuntimeError(
+ "textual.app.wait_for_idle is gone -- tests/_fixtures.fast_keys "
+ "needs updating for this Textual version")
+
+ async def _yield_instead_of_sleeping(min_sleep: float = 0.0,
+ max_sleep: float = 1.0) -> None:
+ await asyncio.sleep(0)
+
+ async def _press(self, *keys: str) -> None:
+ if keys:
+ await self._app._press_keys(keys)
+ await settle(self._app, timeout=5.0)
+
+ textual.app.wait_for_idle = _yield_instead_of_sleeping
+ Pilot.press = _press
+
+
def cache_path(binary: str) -> str:
return binary + ".pristine.i64"