test_dynamic_components.py 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. """Integration tests for var operations."""
  2. import time
  3. from typing import Callable, Generator, TypeVar
  4. import pytest
  5. from selenium.webdriver.common.by import By
  6. from reflex.testing import AppHarness
  7. # pyright: reportOptionalMemberAccess=false, reportGeneralTypeIssues=false, reportUnknownMemberType=false
  8. def DynamicComponents():
  9. """App with var operations."""
  10. import reflex as rx
  11. class DynamicComponentsState(rx.State):
  12. value: int = 10
  13. button: rx.Component = rx.button(
  14. "Click me",
  15. custom_attrs={
  16. "id": "button",
  17. },
  18. )
  19. def got_clicked(self):
  20. self.button = rx.button(
  21. "Clicked",
  22. custom_attrs={
  23. "id": "button",
  24. },
  25. )
  26. @rx.var
  27. def client_token_component(self) -> rx.Component:
  28. return rx.vstack(
  29. rx.el.input(
  30. custom_attrs={
  31. "id": "token",
  32. },
  33. value=self.router.session.client_token,
  34. is_read_only=True,
  35. ),
  36. rx.button(
  37. "Update",
  38. custom_attrs={
  39. "id": "update",
  40. },
  41. on_click=DynamicComponentsState.got_clicked,
  42. ),
  43. )
  44. app = rx.App()
  45. def factorial(n: int) -> int:
  46. if n == 0:
  47. return 1
  48. return n * factorial(n - 1)
  49. @app.add_page
  50. def index():
  51. return rx.vstack(
  52. DynamicComponentsState.client_token_component,
  53. DynamicComponentsState.button,
  54. rx.text(
  55. DynamicComponentsState._evaluate(
  56. lambda state: factorial(state.value), of_type=int
  57. ),
  58. id="factorial",
  59. ),
  60. )
  61. @pytest.fixture(scope="module")
  62. def dynamic_components(tmp_path_factory) -> Generator[AppHarness, None, None]:
  63. """Start VarOperations app at tmp_path via AppHarness.
  64. Args:
  65. tmp_path_factory: pytest tmp_path_factory fixture
  66. Yields:
  67. running AppHarness instance
  68. """
  69. with AppHarness.create(
  70. root=tmp_path_factory.mktemp("dynamic_components"),
  71. app_source=DynamicComponents,
  72. ) as harness:
  73. assert harness.app_instance is not None, "app is not running"
  74. yield harness
  75. T = TypeVar("T")
  76. def poll_for_result(
  77. f: Callable[[], T], exception=Exception, max_attempts=5, seconds_between_attempts=1
  78. ) -> T:
  79. """Poll for a result from a function.
  80. Args:
  81. f: function to call
  82. exception: exception to catch
  83. max_attempts: maximum number of attempts
  84. seconds_between_attempts: seconds to wait between
  85. Returns:
  86. Result of the function
  87. Raises:
  88. AssertionError: if the function does not return a value
  89. """
  90. attempts = 0
  91. while attempts < max_attempts:
  92. try:
  93. return f()
  94. except exception:
  95. attempts += 1
  96. time.sleep(seconds_between_attempts)
  97. raise AssertionError("Function did not return a value")
  98. @pytest.fixture
  99. def driver(dynamic_components: AppHarness):
  100. """Get an instance of the browser open to the dynamic components app.
  101. Args:
  102. dynamic_components: AppHarness for the dynamic components
  103. Yields:
  104. WebDriver instance.
  105. """
  106. driver = dynamic_components.frontend()
  107. try:
  108. token_input = poll_for_result(lambda: driver.find_element(By.ID, "token"))
  109. assert token_input
  110. # wait for the backend connection to send the token
  111. token = dynamic_components.poll_for_value(token_input)
  112. assert token is not None
  113. yield driver
  114. finally:
  115. driver.quit()
  116. def test_dynamic_components(driver, dynamic_components: AppHarness):
  117. """Test that the var operations produce the right results.
  118. Args:
  119. driver: selenium WebDriver open to the app
  120. dynamic_components: AppHarness for the dynamic components
  121. """
  122. button = poll_for_result(lambda: driver.find_element(By.ID, "button"))
  123. assert button
  124. assert button.text == "Click me"
  125. update_button = driver.find_element(By.ID, "update")
  126. assert update_button
  127. update_button.click()
  128. assert (
  129. dynamic_components.poll_for_content(button, exp_not_equal="Click me")
  130. == "Clicked"
  131. )
  132. factorial = poll_for_result(lambda: driver.find_element(By.ID, "factorial"))
  133. assert factorial
  134. assert factorial.text == "3628800"