test_dynamic_components.py 4.0 KB

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