Created
April 16, 2019 15:06
-
-
Save benjamingr/915d0423f8bcf9db6d9fd852c28174ab to your computer and use it in GitHub Desktop.
What happens on a click
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.