Enable real app AppHarness tests to not specify state= (#2358)

This commit is contained in:
Masen Furer 2024-01-05 18:47:31 -07:00 committed by GitHub
parent 51baa94ed5
commit 87844c3f7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 43 additions and 3 deletions

View File

@ -7,5 +7,10 @@ from code.pages import *
import reflex as rx
# Create the app and compile it.
class State(rx.State):
"""Define empty state to allow access to rx.State.router."""
# Create the app.
app = rx.App(style=styles.base_style)

View File

@ -63,6 +63,7 @@ from reflex.state import (
State,
StateManager,
StateUpdate,
code_uses_state_contexts,
)
from reflex.utils import console, exceptions, format, prerequisites, types
from reflex.utils.imports import ImportVar
@ -169,7 +170,8 @@ class App(Base):
deprecation_version="0.3.5",
removal_version="0.4.0",
)
self.state = State
if len(State.class_subclasses) > 0:
self.state = State
# Get the config
config = get_config()
@ -636,7 +638,11 @@ class App(Base):
return
def compile_(self):
"""Compile the app and output it to the pages folder."""
"""Compile the app and output it to the pages folder.
Raises:
RuntimeError: When any page uses state, but no rx.State subclass is defined.
"""
# add the pages before the compile check so App know onload methods
for render, kwargs in DECORATED_PAGES:
self.add_page(render, **kwargs)
@ -701,6 +707,16 @@ class App(Base):
stateful_components_code,
page_components,
) = compiler.compile_stateful_components(self.pages.values())
# Catch "static" apps (that do not define a rx.State subclass) which are trying to access rx.State.
if (
code_uses_state_contexts(stateful_components_code)
and self.state is None
):
raise RuntimeError(
"To access rx.State in frontend components, at least one "
"subclass of rx.State must be defined in the app."
)
compile_results.append((stateful_components_path, stateful_components_code))
result_futures = []

View File

@ -2181,3 +2181,15 @@ class ImmutableMutableProxy(MutableProxy):
return super()._mark_dirty(
wrapped=wrapped, instance=instance, args=args, kwargs=kwargs
)
def code_uses_state_contexts(javascript_code: str) -> bool:
"""Check if the rendered Javascript uses state contexts.
Args:
javascript_code: The Javascript code to check.
Returns:
True if the code attempts to access a member of StateContexts.
"""
return bool("useContext(StateContexts" in javascript_code)

View File

@ -209,6 +209,8 @@ class AppHarness:
reflex.config.get_config(reload=True)
# reset rx.State subclasses
State.class_subclasses.clear()
# Ensure the AppHarness test does not skip State assignment due to running via pytest
os.environ.pop(reflex.constants.PYTEST_CURRENT_TEST, None)
# self.app_module.app.
self.app_module = reflex.utils.prerequisites.get_compiled_app(reload=True)
self.app_instance = self.app_module.app

View File

@ -159,6 +159,11 @@ def get_app(reload: bool = False) -> ModuleType:
sys.path.insert(0, os.getcwd())
app = __import__(module, fromlist=(constants.CompileVars.APP,))
if reload:
from reflex.state import State
# Reset rx.State subclasses to avoid conflict when reloading.
State.class_subclasses.clear()
# Reload the app module.
importlib.reload(app)
return app