
* add support for lifespan tasks * allow passing args to lifespan task * add message to the cancel call * allow asynccontextmanager as lifespan tasks * Fix integration.utils.SessionStorage Previously the SessionStorage util was just looking in localStorage, but the tests didn't catch it because they were asserting the token was not None, rather than asserting it was truthy. Fixed here, because I'm using this structure in the new lifespan test. * If the lifespan task or context takes "app" parameter, pass the FastAPI instance. * test_lifespan: end to end test for register_lifespan_task * In py3.8, Task.cancel takes no args * test_lifespan: use polling to make the test more robust Fix CI failure * Do not allow task_args for better composability --------- Co-authored-by: Masen Furer <m_github@0x26.net>
93 lines
2.5 KiB
Python
93 lines
2.5 KiB
Python
"""Integration tests for links and related components."""
|
|
from typing import Generator
|
|
from urllib.parse import urlsplit
|
|
|
|
import pytest
|
|
from selenium.webdriver.common.by import By
|
|
|
|
from reflex.testing import AppHarness
|
|
|
|
from .utils import SessionStorage, poll_for_navigation
|
|
|
|
|
|
def NavigationApp():
|
|
"""Reflex app with links for navigation."""
|
|
import reflex as rx
|
|
|
|
class State(rx.State):
|
|
is_external: bool = True
|
|
|
|
app = rx.App()
|
|
|
|
@app.add_page
|
|
def index():
|
|
return rx.fragment(
|
|
rx.link("Internal", href="/internal", id="internal"),
|
|
rx.link(
|
|
"External",
|
|
href="/internal",
|
|
is_external=State.is_external,
|
|
id="external",
|
|
),
|
|
rx.link(
|
|
"External Target", href="/internal", target="_blank", id="external2"
|
|
),
|
|
)
|
|
|
|
@rx.page(route="/internal")
|
|
def internal():
|
|
return rx.text("Internal")
|
|
|
|
|
|
@pytest.fixture()
|
|
def navigation_app(tmp_path) -> Generator[AppHarness, None, None]:
|
|
"""Start NavigationApp 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=NavigationApp, # type: ignore
|
|
) as harness:
|
|
yield harness
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_navigation_app(navigation_app: AppHarness):
|
|
"""Type text after moving cursor. Update text on backend.
|
|
|
|
Args:
|
|
navigation_app: harness for NavigationApp app
|
|
"""
|
|
assert navigation_app.app_instance is not None, "app is not running"
|
|
driver = navigation_app.frontend()
|
|
|
|
ss = SessionStorage(driver)
|
|
assert AppHarness._poll_for(lambda: ss.get("token") is not None), "token not found"
|
|
|
|
internal_link = driver.find_element(By.ID, "internal")
|
|
|
|
with poll_for_navigation(driver):
|
|
internal_link.click()
|
|
assert urlsplit(driver.current_url).path == f"/internal/"
|
|
with poll_for_navigation(driver):
|
|
driver.back()
|
|
|
|
external_link = driver.find_element(By.ID, "external")
|
|
external2_link = driver.find_element(By.ID, "external2")
|
|
|
|
external_link.click()
|
|
# Expect a new tab to open
|
|
assert AppHarness._poll_for(lambda: len(driver.window_handles) == 2)
|
|
|
|
# Switch back to the main tab
|
|
driver.switch_to.window(driver.window_handles[0])
|
|
|
|
external2_link.click()
|
|
# Expect another new tab to open
|
|
assert AppHarness._poll_for(lambda: len(driver.window_handles) == 3)
|