reflex/integration/test_radix_themes.py
Masen Furer 67606561d3
[REF-668] Wrap MyApp with radix Theme component (#1867)
* partly add some radix-ui/themes based components

* add @radix-ui/themes integration to top-level app

* WiP: compile _app_wrap based on which component library is used

TODO: working color mode

* WiP get color mode working with agnostic provider

still not perfect, as the RadixColorModeProvider seems to trip hydration errors
when using color_mode_cond component, but for now, this provides a nice balance
between the two libraries and allows them to interoperate.

* WiP template _app.js instead of making a separate wrap file

* WiP: use next-themes for consistent darkmode switching

* strict pin chakra deps

* Move ChakraColorModeProvider to separate js file

* move nasty radix themes js code into js files

* remove chakra from default imports

* chakra fixup import to use .js extension

* Add radix theme typography and layout components

* do NOT special case the radix theme...

avoid templating json and applying it, avoid non-customizable logic

just add the radix Theme component as an app wrap if the user specifies it to
rx.App, and any other app-wrap theme-like component could _also_ be used
without having to change the code.

this also allows different themes for different sections of the app by simply
placing elements inside a different rdxt.theme wrapper.

* Theme uses "radius" not "borderRadius"

* move next-themes to main packages.json

this is always used, regardless of the component library

* test_app: test cases for app_wrap interface

* Finish wrapping Button, Switch, and TextField components

* docstring, comments, static fixups

* debounce: use alias or tag when passing child Element

Fix REF-830

* test_app: ruin my beautiful indentation

* py38 compatibility

* Add event triggers for switch and TextField

* Add type hints for radix theme components

* radix themes fixups from writing the tests

* Add integration test for radix themes components

* test_app: mock out package installation

we only need the compile result, we're not actually trying to install packages

* avoid incompatible version of @emotion/react

* test_radix_themes: include theme_panel component

* next-themes default scheme: "light"

until all of our components look good in dark mode, need to keep the default as
light mode regardless of the system setting.
2023-10-16 15:31:50 -07:00

156 lines
4.4 KiB
Python

"""Integration test for @radix-ui/themes integration."""
from __future__ import annotations
import time
from typing import Generator
import pytest
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from reflex.testing import DEFAULT_TIMEOUT, AppHarness, WebDriver
def RadixThemesApp():
"""App using radix-themes components."""
import reflex as rx
import reflex.components.radix.themes as rdxt
class State(rx.State):
v: str = ""
checked: bool = False
@rx.var
def token(self) -> str:
return self.get_token()
def index() -> rx.Component:
return rdxt.box(
rdxt.text_field(id="token", value=State.token, read_only=True),
rdxt.text_field(id="tf-bare", value=State.v, on_change=State.set_v), # type: ignore
rdxt.text_field_root(
rdxt.text_field_slot("🧸"),
rdxt.text_field(id="tf-slotted", value=State.v, on_change=State.set_v), # type: ignore
),
rdxt.flex(
rdxt.switch(
id="switch1",
checked=State.checked,
on_checked_change=State.set_checked, # type: ignore
),
rx.cond(
State.checked,
rdxt.text("💡", id="bulb"),
rdxt.text("🌙", id="moon"),
),
direction="row",
gap="2",
),
p="5",
)
app = rx.App(
state=State,
theme=rdxt.theme(rdxt.theme_panel(), accent_color="grass"),
)
app.add_page(index)
app.compile()
@pytest.fixture(scope="session")
def radix_themes_app(
tmp_path_factory,
) -> Generator[AppHarness, None, None]:
"""Start BackgroundTask 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(f"radix_themes_app"),
app_source=RadixThemesApp, # type: ignore
) as harness:
yield harness
@pytest.fixture
def driver(radix_themes_app: AppHarness) -> Generator[WebDriver, None, None]:
"""Get an instance of the browser open to the radix_themes_app app.
Args:
radix_themes_app: harness for BackgroundTask app
Yields:
WebDriver instance.
"""
assert radix_themes_app.app_instance is not None, "app is not running"
driver = radix_themes_app.frontend()
try:
yield driver
finally:
driver.quit()
@pytest.fixture()
def token(radix_themes_app: AppHarness, driver: WebDriver) -> str:
"""Get a function that returns the active token.
Args:
radix_themes_app: harness for BackgroundTask app.
driver: WebDriver instance.
Returns:
The token for the connected client
"""
assert radix_themes_app.app_instance is not None
token_input = driver.find_element(By.ID, "token")
assert token_input
# wait for the backend connection to send the token
token = radix_themes_app.poll_for_value(token_input, timeout=DEFAULT_TIMEOUT * 2)
assert token is not None
return token
def test_radix_themes_app(
radix_themes_app: AppHarness,
driver: WebDriver,
token: str,
):
"""Test that background tasks work as expected.
Args:
radix_themes_app: harness for BackgroundTask app.
driver: WebDriver instance.
token: The token for the connected client.
"""
assert radix_themes_app.app_instance is not None
tf_bare = driver.find_element(By.ID, "tf-bare")
tf_slotted = driver.find_element(By.ID, "tf-slotted")
switch = driver.find_element(By.ID, "switch1")
tf_bare.send_keys("hello")
assert radix_themes_app.poll_for_value(tf_slotted) == "hello"
tf_slotted.send_keys(Keys.ARROW_LEFT, Keys.ARROW_LEFT, Keys.ARROW_LEFT, "y je")
assert (
radix_themes_app.poll_for_value(tf_bare, exp_not_equal="hello") == "hey jello"
)
driver.find_element(By.ID, "moon")
switch.click()
time.sleep(0.5)
driver.find_element(By.ID, "bulb")
with pytest.raises(Exception):
driver.find_element(By.ID, "moon")
switch.click()
time.sleep(0.5)
driver.find_element(By.ID, "moon")
with pytest.raises(Exception):
driver.find_element(By.ID, "bulb")