1
0

test_component_state.py 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. """Test that per-component state scaffold works and operates independently."""
  2. from typing import Generator
  3. import pytest
  4. from selenium.webdriver.common.by import By
  5. from reflex.testing import AppHarness
  6. from . import utils
  7. def ComponentStateApp():
  8. """App using per component state."""
  9. import reflex as rx
  10. class MultiCounter(rx.ComponentState):
  11. count: int = 0
  12. def increment(self):
  13. self.count += 1
  14. @classmethod
  15. def get_component(cls, *children, **props):
  16. return rx.vstack(
  17. *children,
  18. rx.heading(cls.count, id=f"count-{props.get('id', 'default')}"),
  19. rx.button(
  20. "Increment",
  21. on_click=cls.increment,
  22. id=f"button-{props.get('id', 'default')}",
  23. ),
  24. **props,
  25. )
  26. app = rx.App(state=rx.State) # noqa
  27. @rx.page()
  28. def index():
  29. mc_a = MultiCounter.create(id="a")
  30. mc_b = MultiCounter.create(id="b")
  31. assert mc_a.State != mc_b.State
  32. return rx.vstack(
  33. mc_a,
  34. mc_b,
  35. rx.button(
  36. "Inc A",
  37. on_click=mc_a.State.increment, # type: ignore
  38. id="inc-a",
  39. ),
  40. )
  41. @pytest.fixture()
  42. def component_state_app(tmp_path) -> Generator[AppHarness, None, None]:
  43. """Start ComponentStateApp app at tmp_path via AppHarness.
  44. Args:
  45. tmp_path: pytest tmp_path fixture
  46. Yields:
  47. running AppHarness instance
  48. """
  49. with AppHarness.create(
  50. root=tmp_path,
  51. app_source=ComponentStateApp, # type: ignore
  52. ) as harness:
  53. yield harness
  54. @pytest.mark.asyncio
  55. async def test_component_state_app(component_state_app: AppHarness):
  56. """Increment counters independently.
  57. Args:
  58. component_state_app: harness for ComponentStateApp app
  59. """
  60. assert component_state_app.app_instance is not None, "app is not running"
  61. driver = component_state_app.frontend()
  62. ss = utils.SessionStorage(driver)
  63. token = AppHarness._poll_for(lambda: ss.get("token") is not None)
  64. assert token is not None
  65. count_a = driver.find_element(By.ID, "count-a")
  66. count_b = driver.find_element(By.ID, "count-b")
  67. button_a = driver.find_element(By.ID, "button-a")
  68. button_b = driver.find_element(By.ID, "button-b")
  69. button_inc_a = driver.find_element(By.ID, "inc-a")
  70. assert count_a.text == "0"
  71. button_a.click()
  72. assert component_state_app.poll_for_content(count_a, exp_not_equal="0") == "1"
  73. button_a.click()
  74. assert component_state_app.poll_for_content(count_a, exp_not_equal="1") == "2"
  75. button_inc_a.click()
  76. assert component_state_app.poll_for_content(count_a, exp_not_equal="2") == "3"
  77. assert count_b.text == "0"
  78. button_b.click()
  79. assert component_state_app.poll_for_content(count_b, exp_not_equal="0") == "1"
  80. button_b.click()
  81. assert component_state_app.poll_for_content(count_b, exp_not_equal="1") == "2"