test_form_submit.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. """Integration tests for forms."""
  2. import time
  3. from typing import Generator
  4. import pytest
  5. from selenium.webdriver.common.by import By
  6. from selenium.webdriver.common.keys import Keys
  7. from reflex.testing import AppHarness
  8. def FormSubmit():
  9. """App with a form using on_submit."""
  10. import reflex as rx
  11. class FormState(rx.State):
  12. form_data: dict = {}
  13. def form_submit(self, form_data: dict):
  14. self.form_data = form_data
  15. app = rx.App(state=FormState)
  16. @app.add_page
  17. def index():
  18. return rx.vstack(
  19. rx.form(
  20. rx.vstack(
  21. rx.input(id="name_input"),
  22. rx.hstack(rx.pin_input(length=4, id="pin_input")),
  23. rx.number_input(id="number_input"),
  24. rx.checkbox(id="bool_input"),
  25. rx.switch(id="bool_input2"),
  26. rx.slider(id="slider_input"),
  27. rx.range_slider(id="range_input"),
  28. rx.radio_group(["option1", "option2"], id="radio_input"),
  29. rx.select(["option1", "option2"], id="select_input"),
  30. rx.text_area(id="text_area_input"),
  31. rx.input(
  32. id="debounce_input",
  33. debounce_timeout=0,
  34. on_change=rx.console_log,
  35. ),
  36. rx.button("Submit", type_="submit"),
  37. ),
  38. on_submit=FormState.form_submit,
  39. ),
  40. rx.spacer(),
  41. height="100vh",
  42. )
  43. app.compile()
  44. @pytest.fixture(scope="session")
  45. def form_submit(tmp_path_factory) -> Generator[AppHarness, None, None]:
  46. """Start FormSubmit app at tmp_path via AppHarness.
  47. Args:
  48. tmp_path_factory: pytest tmp_path_factory fixture
  49. Yields:
  50. running AppHarness instance
  51. """
  52. with AppHarness.create(
  53. root=tmp_path_factory.mktemp("form_submit"),
  54. app_source=FormSubmit, # type: ignore
  55. ) as harness:
  56. assert harness.app_instance is not None, "app is not running"
  57. yield harness
  58. @pytest.fixture
  59. def driver(form_submit: AppHarness):
  60. """GEt an instance of the browser open to the form_submit app.
  61. Args:
  62. form_submit: harness for ServerSideEvent app
  63. Yields:
  64. WebDriver instance.
  65. """
  66. driver = form_submit.frontend()
  67. try:
  68. assert form_submit.poll_for_clients()
  69. yield driver
  70. finally:
  71. driver.quit()
  72. def test_submit(driver, form_submit: AppHarness):
  73. """Fill a form with various different output, submit it to backend and verify
  74. the output.
  75. Args:
  76. driver: selenium WebDriver open to the app
  77. form_submit: harness for FormSubmit app
  78. """
  79. assert form_submit.app_instance is not None, "app is not running"
  80. _, backend_state = list(form_submit.app_instance.state_manager.states.items())[0]
  81. name_input = driver.find_element(By.ID, "name_input")
  82. name_input.send_keys("foo")
  83. pin_inputs = driver.find_elements(By.CLASS_NAME, "chakra-pin-input")
  84. pin_values = ["8", "1", "6", "4"]
  85. for i, pin_input in enumerate(pin_inputs):
  86. pin_input.send_keys(pin_values[i])
  87. number_input = driver.find_element(By.CLASS_NAME, "chakra-numberinput")
  88. buttons = number_input.find_elements(By.XPATH, "//div[@role='button']")
  89. for _ in range(3):
  90. buttons[1].click()
  91. checkbox_input = driver.find_element(By.CLASS_NAME, "chakra-checkbox__control")
  92. checkbox_input.click()
  93. switch_input = driver.find_element(By.CLASS_NAME, "chakra-switch__track")
  94. switch_input.click()
  95. radio_buttons = driver.find_elements(By.CLASS_NAME, "chakra-radio__control")
  96. radio_buttons[1].click()
  97. textarea_input = driver.find_element(By.CLASS_NAME, "chakra-textarea")
  98. textarea_input.send_keys("Some", Keys.ENTER, "Text")
  99. debounce_input = driver.find_element(By.ID, "debounce_input")
  100. debounce_input.send_keys("bar baz")
  101. time.sleep(1)
  102. submit_input = driver.find_element(By.CLASS_NAME, "chakra-button")
  103. submit_input.click()
  104. # wait for the form data to arrive at the backend
  105. AppHarness._poll_for(
  106. lambda: backend_state.form_data != {},
  107. )
  108. assert backend_state.form_data["name_input"] == "foo"
  109. assert backend_state.form_data["pin_input"] == pin_values
  110. assert backend_state.form_data["number_input"] == "-3"
  111. assert backend_state.form_data["bool_input"] is True
  112. assert backend_state.form_data["bool_input2"] is True
  113. assert backend_state.form_data["slider_input"] == "50"
  114. assert backend_state.form_data["range_input"] == ["25", "75"]
  115. assert backend_state.form_data["radio_input"] == "option2"
  116. assert backend_state.form_data["select_input"] == "option1"
  117. assert backend_state.form_data["text_area_input"] == "Some\nText"
  118. assert backend_state.form_data["debounce_input"] == "bar baz"