"""Integration tests for client side storage.""" from __future__ import annotations from typing import Generator import pytest from selenium.common.exceptions import NoSuchElementException from selenium.webdriver.common.by import By from selenium.webdriver.remote.webdriver import WebDriver from reflex.testing import AppHarness from . import utils def LoginSample(): """Sample app for testing login/logout with LocalStorage var.""" import reflex as rx class State(rx.State): auth_token: str = rx.LocalStorage("") def logout(self): self.set_auth_token("") def login(self): self.set_auth_token("12345") yield rx.redirect("/") def index(): return rx.cond( State.is_hydrated & State.auth_token, # type: ignore rx.vstack( rx.heading(State.auth_token, id="auth-token"), rx.button("Logout", on_click=State.logout, id="logout"), ), rx.button("Login", on_click=rx.redirect("/login"), id="login"), ) def login(): return rx.vstack( rx.button("Do it", on_click=State.login, id="doit"), ) app = rx.App(state=rx.State) app.add_page(index) app.add_page(login) @pytest.fixture(scope="module") def login_sample(tmp_path_factory) -> Generator[AppHarness, None, None]: """Start LoginSample app at tmp_path via AppHarness. Args: tmp_path_factory: pytest tmp_path_factory fixture Yields: running AppHarness instance """ with AppHarness.create( root=tmp_path_factory.mktemp("login_sample"), app_source=LoginSample, # type: ignore ) as harness: yield harness @pytest.fixture() def driver(login_sample: AppHarness) -> Generator[WebDriver, None, None]: """Get an instance of the browser open to the login_sample app. Args: login_sample: harness for LoginSample app Yields: WebDriver instance. """ assert login_sample.app_instance is not None, "app is not running" driver = login_sample.frontend() try: yield driver finally: driver.quit() @pytest.fixture() def local_storage(driver: WebDriver) -> Generator[utils.LocalStorage, None, None]: """Get an instance of the local storage helper. Args: driver: WebDriver instance. Yields: Local storage helper. """ ls = utils.LocalStorage(driver) yield ls ls.clear() def test_login_flow( login_sample: AppHarness, driver: WebDriver, local_storage: utils.LocalStorage ): """Test login flow. Args: login_sample: harness for LoginSample app. driver: WebDriver instance. local_storage: Local storage helper. """ assert login_sample.frontend_url is not None local_storage.clear() with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "auth-token") login_button = driver.find_element(By.ID, "login") login_sample.poll_for_content(login_button) with utils.poll_for_navigation(driver): login_button.click() assert driver.current_url.endswith("/login/") do_it_button = driver.find_element(By.ID, "doit") with utils.poll_for_navigation(driver): do_it_button.click() assert driver.current_url == login_sample.frontend_url + "/" def check_auth_token_header(): try: auth_token_header = driver.find_element(By.ID, "auth-token") except NoSuchElementException: return False return auth_token_header.text assert login_sample._poll_for(check_auth_token_header) == "12345" logout_button = driver.find_element(By.ID, "logout") logout_button.click() state_name = login_sample.get_full_state_name(["_state"]) assert login_sample._poll_for( lambda: local_storage[f"{state_name}.auth_token"] == "" ) with pytest.raises(NoSuchElementException): driver.find_element(By.ID, "auth-token")