reflex/integration/test_input.py

92 lines
2.7 KiB
Python

"""Integration tests for text input and related components."""
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 AppHarness
def FullyControlledInput():
"""App using a fully controlled input with debounce wrapper."""
import reflex as rx
class State(rx.State):
text: str = "initial"
app = rx.App(state=State)
@app.add_page
def index():
return rx.debounce_input(
rx.input(
value=State.text,
on_change=State.set_text, # type: ignore
),
debounce_timeout=0,
)
app.compile()
@pytest.fixture()
def fully_controlled_input(tmp_path) -> Generator[AppHarness, None, None]:
"""Start FullyControlledInput app at tmp_path via AppHarness.
Args:
tmp_path: pytest tmp_path fixture
Yields:
running AppHarness instance
"""
with AppHarness.create(
root=tmp_path,
app_source=FullyControlledInput, # type: ignore
) as harness:
yield harness
@pytest.mark.asyncio
async def test_fully_controlled_input(fully_controlled_input: AppHarness):
"""Type text after moving cursor. Update text on backend.
Args:
fully_controlled_input: harness for FullyControlledInput app
"""
assert fully_controlled_input.app_instance is not None, "app is not running"
driver = fully_controlled_input.frontend()
# get a reference to the connected client
assert len(fully_controlled_input.poll_for_clients()) == 1
token, backend_state = list(
fully_controlled_input.app_instance.state_manager.states.items()
)[0]
# find the input and wait for it to have the initial state value
text_input = driver.find_element(By.TAG_NAME, "input")
assert fully_controlled_input.poll_for_value(text_input) == "initial"
# move cursor to home, then to the right and type characters
text_input.send_keys(Keys.HOME, Keys.ARROW_RIGHT)
text_input.send_keys("foo")
assert text_input.get_attribute("value") == "ifoonitial"
assert backend_state.text == "ifoonitial"
# clear the input on the backend
backend_state.text = ""
fully_controlled_input.app_instance.state_manager.set_state(token, backend_state)
await fully_controlled_input.emit_state_updates()
assert backend_state.text == ""
assert (
fully_controlled_input.poll_for_value(text_input, exp_not_equal="ifoonitial")
== ""
)
# type more characters
text_input.send_keys("getting testing done")
time.sleep(0.1)
assert text_input.get_attribute("value") == "getting testing done"
assert backend_state.text == "getting testing done"