user_interaction.py 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. from __future__ import annotations
  2. from typing import TYPE_CHECKING, Generic, Set, Type, TypeVar, Union
  3. from typing_extensions import Self
  4. from nicegui import background_tasks, events, ui
  5. from nicegui.element import Element
  6. if TYPE_CHECKING:
  7. from .user import User
  8. T = TypeVar('T', bound=Element)
  9. class UserInteraction(Generic[T]):
  10. def __init__(self, user: User, elements: Set[T], target: Union[str, Type[T], None]) -> None:
  11. """Interaction object of the simulated user.
  12. This will be returned by the ``find`` method of the ``user`` fixture in pytests.
  13. It can be used to perform interaction with the found elements.
  14. """
  15. self.user = user
  16. for element in elements:
  17. assert isinstance(element, ui.element)
  18. self.elements = elements
  19. self.target = target
  20. def trigger(self, event: str) -> Self:
  21. """Trigger the given event on the elements selected by the simulated user.
  22. Examples: "keydown.enter", "click", ...
  23. """
  24. assert self.user.client
  25. with self.user.client:
  26. for element in self.elements:
  27. for listener in element._event_listeners.values(): # pylint: disable=protected-access
  28. if listener.type != event:
  29. continue
  30. event_arguments = events.GenericEventArguments(sender=element, client=self.user.client, args={})
  31. events.handle_event(listener.handler, event_arguments)
  32. return self
  33. def type(self, text: str) -> Self:
  34. """Type the given text into the selected elements."""
  35. assert self.user.client
  36. with self.user.client:
  37. for element in self.elements:
  38. assert isinstance(element, (ui.input, ui.editor, ui.codemirror))
  39. element.value = (element.value or '') + text
  40. return self
  41. def click(self) -> Self:
  42. """Click the selected elements."""
  43. assert self.user.client
  44. with self.user.client:
  45. for element in self.elements:
  46. if isinstance(element, ui.link):
  47. href = element.props.get('href', '#')
  48. background_tasks.create(self.user.open(href))
  49. return self
  50. if isinstance(element, ui.select):
  51. if element.is_showing_popup:
  52. assert isinstance(self.target, str), 'Target must be string when clicking on ui.select options'
  53. element.set_value(self.target)
  54. element._is_showing_popup = not element.is_showing_popup # pylint: disable=protected-access
  55. return self
  56. for listener in element._event_listeners.values(): # pylint: disable=protected-access
  57. if listener.element_id != element.id:
  58. continue
  59. args = None
  60. if isinstance(element, (ui.checkbox, ui.switch)):
  61. args = not element.value
  62. event_arguments = events.GenericEventArguments(sender=element, client=self.user.client, args=args)
  63. events.handle_event(listener.handler, event_arguments)
  64. return self