Do not stop prop is there is no prop to stop (#2116)

Check that desired event actions are defined on the object passed as the DOM
event before calling them to avoid frontend errors.
This commit is contained in:
Masen Furer 2023-11-02 10:21:41 -07:00 committed by GitHub
parent 6e71393ed5
commit bf20a530df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 48 additions and 6 deletions

View File

@ -1,5 +1,6 @@
"""Ensure stopPropagation and preventDefault work as expected."""
import asyncio
from typing import Callable, Coroutine, Generator
import pytest
@ -21,13 +22,31 @@ def TestEventAction():
def on_click2(self):
self.order.append("on_click2")
@rx.var
def token(self) -> str:
return self.get_token()
class EventFiringComponent(rx.Component):
"""A component that fires onClick event without passing DOM event."""
tag = "EventFiringComponent"
def _get_custom_code(self) -> str | None:
return """
function EventFiringComponent(props) {
return (
<div id={props.id} onClick={(e) => props.onClick("foo")}>
Event Firing Component
</div>
)
}"""
def get_event_triggers(self):
return {"on_click": lambda: []}
def index():
return rx.vstack(
rx.input(value=EventActionState.token, is_read_only=True, id="token"),
rx.input(
value=EventActionState.router.session.client_token,
is_read_only=True,
id="token",
),
rx.button("No events", id="btn-no-events"),
rx.button(
"Stop Prop Only",
@ -90,6 +109,18 @@ def TestEventAction():
).stop_propagation.prevent_default,
id="link-stop-propagation-prevent-default",
),
EventFiringComponent.create(
id="custom-stop-propagation",
on_click=EventActionState.on_click( # type: ignore
"custom-stop-propagation"
).stop_propagation,
),
EventFiringComponent.create(
id="custom-prevent-default",
on_click=EventActionState.on_click( # type: ignore
"custom-prevent-default"
).prevent_default,
),
rx.list(
rx.foreach(
EventActionState.order, # type: ignore
@ -202,6 +233,14 @@ def poll_for_order(
("link-prevent-default", ["on_click:link_prevent_default", "on_click:outer"]),
("link-prevent-default-only", ["on_click:outer"]),
("link-stop-propagation-prevent-default", ["on_click:link_both"]),
(
"custom-stop-propagation",
["on_click:custom-stop-propagation", "on_click:outer"],
),
(
"custom-prevent-default",
["on_click:custom-prevent-default", "on_click:outer"],
),
],
)
@pytest.mark.usefixtures("token")
@ -226,6 +265,9 @@ async def test_event_actions(
prev_url = driver.current_url
el.click()
if "on_click:outer" not in exp_order:
# really make sure the outer event is not fired
await asyncio.sleep(0.5)
await poll_for_order(exp_order)
if element_id.startswith("link") and "prevent-default" not in element_id:

View File

@ -488,10 +488,10 @@ export const useEventLoop = (
// Function to add new events to the event queue.
const addEvents = (events, _e, event_actions) => {
if (event_actions?.preventDefault && _e) {
if (event_actions?.preventDefault && _e?.preventDefault) {
_e.preventDefault();
}
if (event_actions?.stopPropagation && _e) {
if (event_actions?.stopPropagation && _e?.stopPropagation) {
_e.stopPropagation();
}
queueEvents(events, socket)