Skip to content

Commit

Permalink
convert initialEvents to a function (#1982)
Browse files Browse the repository at this point in the history
  • Loading branch information
masenf authored Oct 17, 2023
1 parent b1bab12 commit c3f5f34
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 5 deletions.
144 changes: 144 additions & 0 deletions integration/test_login_flow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"""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.create(
State.is_hydrated & State.auth_token, # type: ignore
rx.vstack(
rx.heading(State.auth_token),
rx.button("Logout", on_click=State.logout),
),
rx.button("Login", on_click=rx.redirect("/login")),
)

def login():
return rx.vstack(
rx.button("Do it", on_click=State.login),
)

app = rx.App(state=State)
app.add_page(index)
app.add_page(login)
app.compile()


@pytest.fixture(scope="session")
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.TAG_NAME, "h2")

login_button = driver.find_element(By.TAG_NAME, "button")
assert login_button.text == "Login"
with utils.poll_for_navigation(driver):
login_button.click()
assert driver.current_url.endswith("/login/")

do_it_button = driver.find_element(By.TAG_NAME, "button")
assert do_it_button.text == "Do it"
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.TAG_NAME, "h2")
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.TAG_NAME, "button")
assert logout_button.text == "Logout"
logout_button.click()

assert login_sample._poll_for(lambda: local_storage["state.auth_token"] == "")
with pytest.raises(NoSuchElementException):
driver.find_element(By.TAG_NAME, "h2")
2 changes: 1 addition & 1 deletion reflex/.templates/jinja/web/pages/index.js.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export default function Component() {

// Route after the initial page hydration.
useEffect(() => {
const change_complete = () => addEvents(initialEvents.map((e) => ({...e})))
const change_complete = () => addEvents(initialEvents())
{{const.router}}.events.on('routeChangeComplete', change_complete)
return () => {
{{const.router}}.events.off('routeChangeComplete', change_complete)
Expand Down
2 changes: 1 addition & 1 deletion reflex/.templates/jinja/web/utils/context.js.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const ColorModeContext = createContext(null);
export const StateContext = createContext(null);
export const EventLoopContext = createContext(null);
export const clientStorage = {{ client_storage|json_dumps }}
export const initialEvents = [
export const initialEvents = () => [
Event('{{state_name}}.{{const.hydrate}}', hydrateClientStorage(clientStorage)),
]
export const isDevMode = {{ is_dev_mode|json_dumps }}
Expand Down
6 changes: 3 additions & 3 deletions reflex/.templates/web/utils/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -468,7 +468,7 @@ const applyClientStorageDelta = (client_storage, delta) => {
/**
* Establish websocket event loop for a NextJS page.
* @param initial_state The initial app state.
* @param initial_events The initial app events.
* @param initial_events Function that returns the initial app events.
* @param client_storage The client storage object from context.js
*
* @returns [state, addEvents, connectError] -
Expand All @@ -478,7 +478,7 @@ const applyClientStorageDelta = (client_storage, delta) => {
*/
export const useEventLoop = (
initial_state = {},
initial_events = [],
initial_events = () => [],
client_storage = {},
) => {
const socket = useRef(null)
Expand All @@ -496,7 +496,7 @@ export const useEventLoop = (
// initial state hydrate
useEffect(() => {
if (router.isReady && !sentHydrate.current) {
addEvents(initial_events.map((e) => ({ ...e })))
addEvents(initial_events())
sentHydrate.current = true
}
}, [router.isReady])
Expand Down

0 comments on commit c3f5f34

Please sign in to comment.