mirror of
https://github.com/Textualize/textual.git
synced 2025-10-17 02:38:12 +03:00
run test context manager
This commit is contained in:
@@ -10,10 +10,15 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- DOMQuery now raises InvalidQueryFormat in response to invalid query strings, rather than cryptic CSS error
|
- DOMQuery now raises InvalidQueryFormat in response to invalid query strings, rather than cryptic CSS error
|
||||||
|
- Dropped quit_after, screenshot, and screenshot_title from App.run, which can all be done via auto_pilot
|
||||||
|
- Widgets are now closed in reversed DOM order
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Added Unmount event
|
||||||
- Added App.run_async method
|
- Added App.run_async method
|
||||||
|
- Added App.run_test context manager
|
||||||
|
- Added auto_pilot to App.run and App.run_async
|
||||||
|
|
||||||
## [0.2.1] - 2022-10-23
|
## [0.2.1] - 2022-10-23
|
||||||
|
|
||||||
|
|||||||
@@ -633,6 +633,38 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
await asyncio.sleep(0.02)
|
await asyncio.sleep(0.02)
|
||||||
await app._animator.wait_for_idle()
|
await app._animator.wait_for_idle()
|
||||||
|
|
||||||
|
@asynccontextmanager
|
||||||
|
async def run_test(self, *, headless: bool = True):
|
||||||
|
"""An asynchronous context manager for testing app.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
headless (bool, optional): Run in headless mode (no output or input). Defaults to True.
|
||||||
|
|
||||||
|
"""
|
||||||
|
from .pilot import Pilot
|
||||||
|
|
||||||
|
app = self
|
||||||
|
app_ready_event = asyncio.Event()
|
||||||
|
|
||||||
|
def on_app_ready() -> None:
|
||||||
|
"""Called when app is ready to process events."""
|
||||||
|
app_ready_event.set()
|
||||||
|
|
||||||
|
async def run_app(app) -> None:
|
||||||
|
await app._process_messages(ready_callback=on_app_ready, headless=headless)
|
||||||
|
|
||||||
|
# Launch the app in the "background"
|
||||||
|
asyncio.create_task(run_app(app))
|
||||||
|
|
||||||
|
# Wait until the app has performed all startup routines.
|
||||||
|
await app_ready_event.wait()
|
||||||
|
|
||||||
|
# Context manager returns pilot object to manipulate the app
|
||||||
|
yield Pilot(app)
|
||||||
|
|
||||||
|
# Shutdown the app cleanly
|
||||||
|
await app._shutdown()
|
||||||
|
|
||||||
async def run_async(
|
async def run_async(
|
||||||
self,
|
self,
|
||||||
*,
|
*,
|
||||||
@@ -655,8 +687,16 @@ class App(Generic[ReturnType], DOMNode):
|
|||||||
async def app_ready() -> None:
|
async def app_ready() -> None:
|
||||||
"""Called by the message loop when the app is ready."""
|
"""Called by the message loop when the app is ready."""
|
||||||
if auto_pilot is not None:
|
if auto_pilot is not None:
|
||||||
|
|
||||||
|
async def run_auto_pilot(pilot) -> None:
|
||||||
|
try:
|
||||||
|
await auto_pilot(pilot)
|
||||||
|
except Exception:
|
||||||
|
app.exit()
|
||||||
|
raise
|
||||||
|
|
||||||
pilot = Pilot(app)
|
pilot = Pilot(app)
|
||||||
asyncio.create_task(auto_pilot(pilot))
|
asyncio.create_task(run_auto_pilot(pilot))
|
||||||
|
|
||||||
await app._process_messages(ready_callback=app_ready, headless=headless)
|
await app._process_messages(ready_callback=app_ready, headless=headless)
|
||||||
await app._shutdown()
|
await app._shutdown()
|
||||||
|
|||||||
@@ -17,10 +17,15 @@ class Pilot:
|
|||||||
self._app = app
|
self._app = app
|
||||||
|
|
||||||
def __rich_repr__(self) -> rich.repr.Result:
|
def __rich_repr__(self) -> rich.repr.Result:
|
||||||
yield "app", "self._app"
|
yield "app", self._app
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def app(self) -> App:
|
def app(self) -> App:
|
||||||
|
"""Get a reference to the application.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
App: The App instance.
|
||||||
|
"""
|
||||||
return self._app
|
return self._app
|
||||||
|
|
||||||
async def press(self, *keys: str) -> None:
|
async def press(self, *keys: str) -> None:
|
||||||
@@ -39,3 +44,11 @@ class Pilot:
|
|||||||
delay (float, optional): Seconds to pause. Defaults to 50ms.
|
delay (float, optional): Seconds to pause. Defaults to 50ms.
|
||||||
"""
|
"""
|
||||||
await asyncio.sleep(delay)
|
await asyncio.sleep(delay)
|
||||||
|
|
||||||
|
async def exit(self, result: object) -> None:
|
||||||
|
"""Exit the app with the given result.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
result (object): The app result returned by `run` or `run_async`.
|
||||||
|
"""
|
||||||
|
self.app.exit(result)
|
||||||
|
|||||||
Reference in New Issue
Block a user