53 lines
2.0 KiB
Python
53 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import runpy
|
|
from collections.abc import AsyncGenerator
|
|
from contextlib import asynccontextmanager
|
|
from pathlib import Path
|
|
from typing import Callable
|
|
|
|
import httpx
|
|
|
|
from .. import core, ui
|
|
from ..functions.download import download
|
|
from ..functions.navigate import Navigate
|
|
from ..functions.notify import notify
|
|
from .general import nicegui_reset_globals, prepare_simulation
|
|
from .user import User
|
|
|
|
|
|
@asynccontextmanager
|
|
async def user_simulation(
|
|
root: Callable | None = None, *, main_file: str | os.PathLike | None = None,
|
|
) -> AsyncGenerator[User, None]:
|
|
"""Context manager for test user simulation.
|
|
|
|
This context manager yields a ``User`` connected to a NiceGUI app within an isolated test context.
|
|
|
|
:param root: root function which is passed directly to ``ui.run``; mutually exclusive with ``main_file`` argument.
|
|
:param main_file: path to a NiceGUI main file executed via ``runpy.run_path``; mutually exclusive with ``root`` argument.
|
|
"""
|
|
if main_file is not None and root is not None:
|
|
raise ValueError('Cannot specify both `main_file` and `root` function simultaneously.')
|
|
|
|
with nicegui_reset_globals():
|
|
os.environ['NICEGUI_USER_SIMULATION'] = 'true'
|
|
try:
|
|
if main_file is not None:
|
|
if not Path(main_file).exists():
|
|
raise FileNotFoundError(f'Main file not found at {main_file}')
|
|
runpy.run_path(str(main_file), run_name='__main__')
|
|
else:
|
|
prepare_simulation()
|
|
ui.run(root, storage_secret='simulated secret')
|
|
|
|
async with core.app.router.lifespan_context(core.app):
|
|
async with httpx.AsyncClient(transport=httpx.ASGITransport(core.app), base_url='http://test') as client:
|
|
yield User(client)
|
|
finally:
|
|
os.environ.pop('NICEGUI_USER_SIMULATION', None)
|
|
ui.navigate = Navigate()
|
|
ui.notify = notify
|
|
ui.download = download
|