test_login_flow.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. """Integration tests for client side storage."""
  2. from __future__ import annotations
  3. from typing import Generator
  4. import pytest
  5. from selenium.common.exceptions import NoSuchElementException
  6. from selenium.webdriver.common.by import By
  7. from selenium.webdriver.remote.webdriver import WebDriver
  8. from reflex.testing import AppHarness
  9. from . import utils
  10. def LoginSample():
  11. """Sample app for testing login/logout with LocalStorage var."""
  12. import reflex as rx
  13. class State(rx.State):
  14. auth_token: str = rx.LocalStorage("")
  15. def logout(self):
  16. self.set_auth_token("")
  17. def login(self):
  18. self.set_auth_token("12345")
  19. yield rx.redirect("/")
  20. def index():
  21. return rx.Cond.create(
  22. State.is_hydrated & State.auth_token, # type: ignore
  23. rx.vstack(
  24. rx.heading(State.auth_token, id="auth-token"),
  25. rx.button("Logout", on_click=State.logout, id="logout"),
  26. ),
  27. rx.button("Login", on_click=rx.redirect("/login"), id="login"),
  28. )
  29. def login():
  30. return rx.vstack(
  31. rx.button("Do it", on_click=State.login, id="doit"),
  32. )
  33. app = rx.App(state=rx.State)
  34. app.add_page(index)
  35. app.add_page(login)
  36. app.compile()
  37. @pytest.fixture(scope="session")
  38. def login_sample(tmp_path_factory) -> Generator[AppHarness, None, None]:
  39. """Start LoginSample app at tmp_path via AppHarness.
  40. Args:
  41. tmp_path_factory: pytest tmp_path_factory fixture
  42. Yields:
  43. running AppHarness instance
  44. """
  45. with AppHarness.create(
  46. root=tmp_path_factory.mktemp("login_sample"),
  47. app_source=LoginSample, # type: ignore
  48. ) as harness:
  49. yield harness
  50. @pytest.fixture()
  51. def driver(login_sample: AppHarness) -> Generator[WebDriver, None, None]:
  52. """Get an instance of the browser open to the login_sample app.
  53. Args:
  54. login_sample: harness for LoginSample app
  55. Yields:
  56. WebDriver instance.
  57. """
  58. assert login_sample.app_instance is not None, "app is not running"
  59. driver = login_sample.frontend()
  60. try:
  61. yield driver
  62. finally:
  63. driver.quit()
  64. @pytest.fixture()
  65. def local_storage(driver: WebDriver) -> Generator[utils.LocalStorage, None, None]:
  66. """Get an instance of the local storage helper.
  67. Args:
  68. driver: WebDriver instance.
  69. Yields:
  70. Local storage helper.
  71. """
  72. ls = utils.LocalStorage(driver)
  73. yield ls
  74. ls.clear()
  75. def test_login_flow(
  76. login_sample: AppHarness, driver: WebDriver, local_storage: utils.LocalStorage
  77. ):
  78. """Test login flow.
  79. Args:
  80. login_sample: harness for LoginSample app.
  81. driver: WebDriver instance.
  82. local_storage: Local storage helper.
  83. """
  84. assert login_sample.frontend_url is not None
  85. local_storage.clear()
  86. with pytest.raises(NoSuchElementException):
  87. driver.find_element(By.ID, "auth-token")
  88. login_button = driver.find_element(By.ID, "login")
  89. login_sample.poll_for_content(login_button)
  90. with utils.poll_for_navigation(driver):
  91. login_button.click()
  92. assert driver.current_url.endswith("/login/")
  93. do_it_button = driver.find_element(By.ID, "doit")
  94. with utils.poll_for_navigation(driver):
  95. do_it_button.click()
  96. assert driver.current_url == login_sample.frontend_url + "/"
  97. def check_auth_token_header():
  98. try:
  99. auth_token_header = driver.find_element(By.ID, "auth-token")
  100. except NoSuchElementException:
  101. return False
  102. return auth_token_header.text
  103. assert login_sample._poll_for(check_auth_token_header) == "12345"
  104. logout_button = driver.find_element(By.ID, "logout")
  105. logout_button.click()
  106. assert login_sample._poll_for(lambda: local_storage["state.state.auth_token"] == "")
  107. with pytest.raises(NoSuchElementException):
  108. driver.find_element(By.ID, "auth-token")