Skip to content

Instantly share code, notes, and snippets.

@benjamingr
Created April 16, 2019 15:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save benjamingr/915d0423f8bcf9db6d9fd852c28174ab to your computer and use it in GitHub Desktop.
Save benjamingr/915d0423f8bcf9db6d9fd852c28174ab to your computer and use it in GitHub Desktop.
What happens on a click
// actual differences (in chrome, IE, Firefox, Safari an Edge are all different) are:
// - behavior in disabled 'form' controls
// - phoning to home base (not here, it's defined elsewhere, can dig it up)
// - dealing with clicks dispatching clicks 'recursively'
// this is HTMLElement::click
void HTMLElement::click() {
DispatchSimulatedClick(nullptr, kSendNoEvents,
SimulatedClickCreationScope::kFromScript);
}
// this is the DispatchSimulatedClick method in event_dispatcher.cc the "heart" of the difference
void EventDispatcher::DispatchSimulatedClick(
Node& node,
Event* underlying_event,
SimulatedClickMouseEventOptions mouse_event_options,
SimulatedClickCreationScope creation_scope) {
// This persistent vector doesn't cause leaks, because added Nodes are removed
// before dispatchSimulatedClick() returns. This vector is here just to
// prevent the code from running into an infinite recursion of
// dispatchSimulatedClick().
DEFINE_STATIC_LOCAL(Persistent<HeapHashSet<Member<Node>>>,
nodes_dispatching_simulated_clicks,
(MakeGarbageCollected<HeapHashSet<Member<Node>>>()));
if (IsDisabledFormControl(&node))
return;
if (nodes_dispatching_simulated_clicks->Contains(&node))
return;
nodes_dispatching_simulated_clicks->insert(&node);
if (mouse_event_options == kSendMouseOverUpDownEvents)
EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseover,
node.GetDocument().domWindow(),
underlying_event, creation_scope))
.Dispatch();
if (mouse_event_options != kSendNoEvents) {
EventDispatcher(node, *MouseEvent::Create(event_type_names::kMousedown,
node.GetDocument().domWindow(),
underlying_event, creation_scope))
.Dispatch();
node.SetActive(true);
EventDispatcher(node, *MouseEvent::Create(event_type_names::kMouseup,
node.GetDocument().domWindow(),
underlying_event, creation_scope))
.Dispatch();
}
// Some elements (e.g. the color picker) may set active state to true before
// calling this method and expect the state to be reset during the call.
node.SetActive(false);
// always send click
EventDispatcher(node, *MouseEvent::Create(event_type_names::kClick,
node.GetDocument().domWindow(),
underlying_event, creation_scope))
.Dispatch();
nodes_dispatching_simulated_clicks->erase(&node);
}
@benjamingr
Copy link
Author

And there is a separate path for 'real' clicks as well as clicks through the debugger (Input.dispatchMouseEvent which is essentially what Selenium calls).

This is part of why automation is hard.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment